From 588727c7e2b8954ec3dbde293cf4c4d68b119f9b Mon Sep 17 00:00:00 2001 From: xue <> Date: Mon, 19 Jun 2006 18:38:29 +0000 Subject: Merge from 3.0 branch till 1185. --- buildscripts/Benchmark/Iterate.php | 167 + buildscripts/Benchmark/LICENSE | 22 + buildscripts/Benchmark/Profiler.php | 447 ++ buildscripts/Benchmark/Timer.php | 319 ++ buildscripts/Benchmark/doc/timer_example.php | 18 + .../PHPUnit2/Extensions/ExceptionTestCase.php | 122 + .../PHPUnit2/Extensions/PerformanceTestCase.php | 128 + buildscripts/PHPUnit2/Extensions/RepeatedTest.php | 138 + buildscripts/PHPUnit2/Extensions/TestDecorator.php | 174 + buildscripts/PHPUnit2/Extensions/TestSetup.php | 154 + buildscripts/PHPUnit2/Framework/Assert.php | 626 +++ .../PHPUnit2/Framework/AssertionFailedError.php | 80 + .../PHPUnit2/Framework/ComparisonFailure.php | 153 + buildscripts/PHPUnit2/Framework/Error.php | 88 + buildscripts/PHPUnit2/Framework/IncompleteTest.php | 72 + .../PHPUnit2/Framework/IncompleteTestError.php | 75 + buildscripts/PHPUnit2/Framework/Test.php | 87 + buildscripts/PHPUnit2/Framework/TestCase.php | 292 ++ buildscripts/PHPUnit2/Framework/TestFailure.php | 154 + buildscripts/PHPUnit2/Framework/TestListener.php | 135 + buildscripts/PHPUnit2/Framework/TestResult.php | 447 ++ buildscripts/PHPUnit2/Framework/TestSuite.php | 554 ++ buildscripts/PHPUnit2/Framework/Warning.php | 94 + buildscripts/PHPUnit2/Runner/BaseTestRunner.php | 283 + .../PHPUnit2/Runner/IncludePathTestCollector.php | 184 + .../PHPUnit2/Runner/StandardTestSuiteLoader.php | 129 + buildscripts/PHPUnit2/Runner/TestCollector.php | 77 + buildscripts/PHPUnit2/Runner/TestSuiteLoader.php | 85 + buildscripts/PHPUnit2/Runner/Version.php | 90 + buildscripts/PHPUnit2/TextUI/ResultPrinter.php | 356 ++ buildscripts/PHPUnit2/TextUI/TestRunner.php | 622 +++ .../PHPUnit2/Util/CodeCoverage/Renderer.php | 225 + .../PHPUnit2/Util/CodeCoverage/Renderer/HTML.php | 191 + .../PHPUnit2/Util/CodeCoverage/Renderer/Text.php | 125 + buildscripts/PHPUnit2/Util/ErrorHandler.php | 77 + buildscripts/PHPUnit2/Util/Fileloader.php | 109 + buildscripts/PHPUnit2/Util/Filter.php | 263 + buildscripts/PHPUnit2/Util/Log/PEAR.php | 220 + buildscripts/PHPUnit2/Util/Log/XML.php | 356 ++ buildscripts/PHPUnit2/Util/Printer.php | 116 + buildscripts/PHPUnit2/Util/Skeleton.php | 340 ++ .../PHPUnit2/Util/TestDox/NamePrettifier.php | 165 + .../PHPUnit2/Util/TestDox/ResultPrinter.php | 299 ++ .../PHPUnit2/Util/TestDox/ResultPrinter/HTML.php | 120 + .../PHPUnit2/Util/TestDox/ResultPrinter/Text.php | 102 + buildscripts/PHPUnit2/pear-phpunit | 41 + buildscripts/PHPUnit2/pear-phpunit.bat | 39 + buildscripts/PhpDocumentor/PHPLICENSE.txt | 69 + buildscripts/PhpDocumentor/new_phpdoc.php | 662 +++ buildscripts/PhpDocumentor/pear-phpdoc | 38 + buildscripts/PhpDocumentor/pear-phpdoc.bat | 145 + buildscripts/PhpDocumentor/phpDocumentor.ini | 118 + .../PhpDocumentor/phpDocumentor/Classes.inc | 1068 ++++ .../PhpDocumentor/phpDocumentor/Converter.inc | 5189 +++++++++++++++++++ .../Converters/CHM/default/CHMdefaultConverter.inc | 1753 +++++++ .../CHM/default/templates/default/options.ini | 507 ++ .../templates/default/templates/basicindex.tpl | 21 + .../default/templates/default/templates/blank.tpl | 13 + .../default/templates/default/templates/class.tpl | 94 + .../templates/default/templates/classleft.tpl | 8 + .../templates/default/templates/classtrees.tpl | 12 + .../default/templates/default/templates/const.tpl | 29 + .../templates/default/templates/contents.hhc.tpl | 11 + .../default/templates/default/templates/define.tpl | 33 + .../templates/default/templates/docblock.tpl | 31 + .../templates/default/templates/elementindex.tpl | 9 + .../default/templates/default/templates/errors.tpl | 21 + .../templates/default/templates/fileleft.tpl | 8 + .../templates/default/templates/filesource.tpl | 6 + .../default/templates/default/templates/footer.tpl | 8 + .../templates/default/templates/function.tpl | 44 + .../default/templates/default/templates/global.tpl | 32 + .../default/templates/default/templates/header.tpl | 22 + .../default/templates/default/templates/hhp.tpl | 17 + .../templates/default/templates/include.tpl | 26 + .../templates/default/templates/index.hhk.tpl | 8 + .../default/templates/default/templates/index.tpl | 24 + .../templates/default/templates/media/bg_left.png | Bin 0 -> 991 bytes .../default/templates/media/stylesheet.css | 129 + .../default/templates/default/templates/method.tpl | 55 + .../templates/default/templates/packages.tpl | 3 + .../default/templates/default/templates/page.tpl | 34 + .../default/templates/pkgelementindex.tpl | 14 + .../default/templates/default/templates/ric.tpl | 6 + .../templates/default/templates/tocentry.tpl | 11 + .../templates/default/templates/todolist.tpl | 14 + .../templates/default/templates/tutorial.tpl | 32 + .../templates/default/templates/tutorial_toc.tpl | 29 + .../templates/default/templates/tutorial_tree.tpl | 5 + .../default/templates/default/templates/var.tpl | 30 + .../Converters/HTML/Smarty/HTMLSmartyConverter.inc | 1779 +++++++ .../HTML/Smarty/templates/PradoSoft/options.ini | 577 +++ .../templates/PradoSoft/templates/__tags.tpl | 13 + .../PradoSoft/templates/_class_declaration.tpl | 38 + .../PradoSoft/templates/_class_description.tpl | 7 + .../templates/PradoSoft/templates/_class_list.tpl | 1 + .../PradoSoft/templates/_constant_details.tpl | 33 + .../PradoSoft/templates/_constant_summary.tpl | 22 + .../PradoSoft/templates/_constructor_details.tpl | 55 + .../PradoSoft/templates/_constructor_summary.tpl | 25 + .../PradoSoft/templates/_destructor_details.tpl | 55 + .../PradoSoft/templates/_destructor_summary.tpl | 27 + .../templates/PradoSoft/templates/_footer.tpl | 1 + .../PradoSoft/templates/_get_constant_type.tpl | 10 + .../templates/PradoSoft/templates/_header.tpl | 4 + .../PradoSoft/templates/_inherited_constants.tpl | 34 + .../PradoSoft/templates/_inherited_methods.tpl | 42 + .../PradoSoft/templates/_inheritence_tree.tpl | 3 + .../PradoSoft/templates/_method_details.tpl | 101 + .../PradoSoft/templates/_method_summary.tpl | 61 + .../templates/PradoSoft/templates/_sub_classes.tpl | 19 + .../Smarty/templates/PradoSoft/templates/_tags.tpl | 13 + .../templates/PradoSoft/templates/basicindex.tpl | 18 + .../Smarty/templates/PradoSoft/templates/blank.tpl | 5 + .../Smarty/templates/PradoSoft/templates/class.tpl | 29 + .../templates/PradoSoft/templates/classleft.tpl | 9 + .../templates/PradoSoft/templates/classtrees.tpl | 8 + .../Smarty/templates/PradoSoft/templates/const.tpl | 14 + .../templates/PradoSoft/templates/define.tpl | 32 + .../templates/PradoSoft/templates/docblock.tpl | 15 + .../templates/PradoSoft/templates/elementindex.tpl | 5 + .../templates/PradoSoft/templates/errors.tpl | 21 + .../PradoSoft/templates/examplesource.tpl | 6 + .../templates/PradoSoft/templates/fileleft.tpl | 10 + .../templates/PradoSoft/templates/filesource.tpl | 8 + .../templates/PradoSoft/templates/footer.tpl | 25 + .../templates/PradoSoft/templates/function.tpl | 48 + .../templates/PradoSoft/templates/global.tpl | 40 + .../templates/PradoSoft/templates/header.tpl | 121 + .../templates/PradoSoft/templates/include.tpl | 9 + .../Smarty/templates/PradoSoft/templates/index.tpl | 7 + .../PradoSoft/templates/media/background.png | Bin 0 -> 238 bytes .../templates/PradoSoft/templates/media/empty.png | Bin 0 -> 206 bytes .../templates/PradoSoft/templates/media/style.css | 197 + .../templates/PradoSoft/templates/method.tpl | 58 + .../templates/PradoSoft/templates/packages.tpl | 3 + .../Smarty/templates/PradoSoft/templates/page.tpl | 31 + .../PradoSoft/templates/pkgelementindex.tpl | 5 + .../Smarty/templates/PradoSoft/templates/ric.tpl | 6 + .../templates/PradoSoft/templates/todolist.tpl | 14 + .../templates/PradoSoft/templates/tutorial.tpl | 32 + .../templates/PradoSoft/templates/tutorial_toc.tpl | 29 + .../PradoSoft/templates/tutorial_tree.tpl | 5 + .../Smarty/templates/PradoSoft/templates/var.tpl | 28 + .../Converters/HTML/frames/HTMLframesConverter.inc | 1747 +++++++ .../HTML/frames/templates/default/options.ini | 577 +++ .../templates/default/templates/basicindex.tpl | 47 + .../frames/templates/default/templates/blank.tpl | 13 + .../frames/templates/default/templates/class.tpl | 402 ++ .../templates/default/templates/classtrees.tpl | 11 + .../frames/templates/default/templates/const.tpl | 18 + .../frames/templates/default/templates/define.tpl | 24 + .../templates/default/templates/docblock.tpl | 14 + .../templates/default/templates/elementindex.tpl | 12 + .../frames/templates/default/templates/errors.tpl | 21 + .../templates/default/templates/examplesource.tpl | 6 + .../templates/default/templates/filesource.tpl | 8 + .../frames/templates/default/templates/footer.tpl | 8 + .../templates/default/templates/function.tpl | 44 + .../frames/templates/default/templates/global.tpl | 26 + .../frames/templates/default/templates/header.tpl | 12 + .../frames/templates/default/templates/include.tpl | 16 + .../frames/templates/default/templates/index.tpl | 24 + .../templates/default/templates/left_frame.tpl | 149 + .../templates/default/templates/media/banner.css | 32 + .../default/templates/media/stylesheet.css | 144 + .../frames/templates/default/templates/method.tpl | 61 + .../frames/templates/default/templates/page.tpl | 211 + .../default/templates/pkgelementindex.tpl | 17 + .../frames/templates/default/templates/ric.tpl | 6 + .../templates/default/templates/todolist.tpl | 14 + .../templates/default/templates/top_frame.tpl | 43 + .../templates/default/templates/tutorial.tpl | 13 + .../templates/default/templates/tutorial_nav.tpl | 41 + .../templates/default/templates/tutorial_toc.tpl | 39 + .../templates/default/templates/tutorial_tree.tpl | 6 + .../frames/templates/default/templates/var.tpl | 44 + .../PhpDocumentor/phpDocumentor/DescHTML.inc | 241 + .../PhpDocumentor/phpDocumentor/DocBlock/Lexer.inc | 701 +++ .../PhpDocumentor/phpDocumentor/DocBlockTags.inc | 984 ++++ .../PhpDocumentor/phpDocumentor/Errors.inc | 793 +++ .../PhpDocumentor/phpDocumentor/EventStack.inc | 78 + .../phpDocumentor/HighlightParser.inc | 2354 +++++++++ .../PhpDocumentor/phpDocumentor/InlineTags.inc | 854 +++ .../phpDocumentor/IntermediateParser.inc | 1832 +++++++ buildscripts/PhpDocumentor/phpDocumentor/Io.inc | 868 ++++ .../PhpDocumentor/phpDocumentor/LinkClasses.inc | 206 + .../phpDocumentor/PackagePageElements.inc | 387 ++ .../PhpDocumentor/phpDocumentor/Parser.inc | 3185 ++++++++++++ .../PhpDocumentor/phpDocumentor/ParserData.inc | 725 +++ .../phpDocumentor/ParserDescCleanup.inc | 1456 ++++++ .../PhpDocumentor/phpDocumentor/ParserDocBlock.inc | 1165 +++++ .../PhpDocumentor/phpDocumentor/ParserElements.inc | 1910 +++++++ .../phpDocumentor/ProceduralPages.inc | 782 +++ .../PhpDocumentor/phpDocumentor/Publisher.inc | 84 + .../PhpDocumentor/phpDocumentor/Setup.inc.php | 785 +++ .../PhpDocumentor/phpDocumentor/Smarty-2.6.0/BUGS | 7 + .../phpDocumentor/Smarty-2.6.0/COPYING.lib | 458 ++ .../phpDocumentor/Smarty-2.6.0/ChangeLog | 5421 ++++++++++++++++++++ .../PhpDocumentor/phpDocumentor/Smarty-2.6.0/FAQ | 284 + .../phpDocumentor/Smarty-2.6.0/INSTALL | 29 + .../PhpDocumentor/phpDocumentor/Smarty-2.6.0/NEWS | 733 +++ .../phpDocumentor/Smarty-2.6.0/README | 80 + .../phpDocumentor/Smarty-2.6.0/RELEASE_NOTES | 423 ++ .../PhpDocumentor/phpDocumentor/Smarty-2.6.0/TODO | 12 + .../Smarty-2.6.0/libs/Config_File.class.php | 365 ++ .../Smarty-2.6.0/libs/Smarty.class.php | 2010 ++++++++ .../Smarty-2.6.0/libs/Smarty_Compiler.class.php | 2123 ++++++++ .../libs/core/core.assemble_plugin_filepath.php | 62 + .../libs/core/core.assign_smarty_interface.php | 43 + .../libs/core/core.create_dir_structure.php | 79 + .../libs/core/core.display_debug_console.php | 60 + .../libs/core/core.get_include_path.php | 44 + .../Smarty-2.6.0/libs/core/core.get_microtime.php | 23 + .../libs/core/core.get_php_resource.php | 80 + .../Smarty-2.6.0/libs/core/core.is_secure.php | 59 + .../Smarty-2.6.0/libs/core/core.is_trusted.php | 50 + .../Smarty-2.6.0/libs/core/core.load_plugins.php | 125 + .../libs/core/core.load_resource_plugin.php | 74 + .../libs/core/core.process_cached_inserts.php | 71 + .../libs/core/core.process_compiled_include.php | 32 + .../libs/core/core.read_cache_file.php | 111 + .../Smarty-2.6.0/libs/core/core.rm_auto.php | 71 + .../Smarty-2.6.0/libs/core/core.rmdir.php | 55 + .../libs/core/core.run_insert_handler.php | 71 + .../libs/core/core.smarty_include_php.php | 50 + .../libs/core/core.write_cache_file.php | 73 + .../libs/core/core.write_compiled_include.php | 59 + .../libs/core/core.write_compiled_resource.php | 37 + .../Smarty-2.6.0/libs/core/core.write_file.php | 48 + .../phpDocumentor/Smarty-2.6.0/libs/debug.tpl | 64 + .../Smarty-2.6.0/libs/plugins/block.strip.php | 35 + .../Smarty-2.6.0/libs/plugins/block.textformat.php | 83 + .../Smarty-2.6.0/libs/plugins/function.assign.php | 38 + .../libs/plugins/function.assign_debug_info.php | 39 + .../libs/plugins/function.config_load.php | 130 + .../Smarty-2.6.0/libs/plugins/function.counter.php | 88 + .../Smarty-2.6.0/libs/plugins/function.cycle.php | 119 + .../Smarty-2.6.0/libs/plugins/function.debug.php | 35 + .../Smarty-2.6.0/libs/plugins/function.eval.php | 48 + .../Smarty-2.6.0/libs/plugins/function.fetch.php | 217 + .../libs/plugins/function.html_checkboxes.php | 135 + .../libs/plugins/function.html_image.php | 143 + .../libs/plugins/function.html_options.php | 118 + .../libs/plugins/function.html_radios.php | 138 + .../libs/plugins/function.html_select_date.php | 243 + .../libs/plugins/function.html_select_time.php | 163 + .../libs/plugins/function.html_table.php | 113 + .../Smarty-2.6.0/libs/plugins/function.mailto.php | 140 + .../Smarty-2.6.0/libs/plugins/function.math.php | 82 + .../Smarty-2.6.0/libs/plugins/function.popup.php | 87 + .../libs/plugins/function.popup_init.php | 39 + .../libs/plugins/function.var_dump.php | 20 + .../libs/plugins/modifier.capitalize.php | 25 + .../Smarty-2.6.0/libs/plugins/modifier.cat.php | 33 + .../libs/plugins/modifier.count_characters.php | 31 + .../libs/plugins/modifier.count_paragraphs.php | 28 + .../libs/plugins/modifier.count_sentences.php | 28 + .../libs/plugins/modifier.count_words.php | 32 + .../libs/plugins/modifier.date_format.php | 43 + .../libs/plugins/modifier.debug_print_var.php | 57 + .../Smarty-2.6.0/libs/plugins/modifier.default.php | 31 + .../Smarty-2.6.0/libs/plugins/modifier.escape.php | 63 + .../libs/plugins/modifier.htmlentities.php | 18 + .../Smarty-2.6.0/libs/plugins/modifier.indent.php | 27 + .../Smarty-2.6.0/libs/plugins/modifier.lower.php | 25 + .../Smarty-2.6.0/libs/plugins/modifier.nl2br.php | 35 + .../libs/plugins/modifier.rawurlencode.php | 18 + .../libs/plugins/modifier.regex_replace.php | 29 + .../Smarty-2.6.0/libs/plugins/modifier.replace.php | 29 + .../Smarty-2.6.0/libs/plugins/modifier.spacify.php | 29 + .../libs/plugins/modifier.string_format.php | 28 + .../Smarty-2.6.0/libs/plugins/modifier.strip.php | 33 + .../libs/plugins/modifier.strip_tags.php | 31 + .../libs/plugins/modifier.truncate.php | 43 + .../Smarty-2.6.0/libs/plugins/modifier.upper.php | 25 + .../libs/plugins/modifier.wordwrap.php | 28 + .../libs/plugins/outputfilter.trimwhitespace.php | 75 + .../libs/plugins/shared.escape_special_chars.php | 30 + .../libs/plugins/shared.make_timestamp.php | 43 + .../Smarty-2.6.0/misc/smarty_icon.README | 6 + .../Smarty-2.6.0/misc/smarty_icon.gif | Bin 0 -> 1102 bytes .../phpDocumentor/TutorialHighlightParser.inc | 491 ++ .../PhpDocumentor/phpDocumentor/WordParser.inc | 325 ++ .../phpDocumentor/XMLpackagePageParser.inc | 554 ++ .../PhpDocumentor/phpDocumentor/clone.inc.php | 13 + .../PhpDocumentor/phpDocumentor/clone5.inc.php | 14 + .../PhpDocumentor/phpDocumentor/common.inc.php | 244 + .../PhpDocumentor/phpDocumentor/find_phpdoc.php | 32 + .../phpDocumentor/phpDocumentorTParser.inc | 2615 ++++++++++ .../phpDocumentor/phpDocumentorTWordParser.inc | 311 ++ .../PhpDocumentor/phpDocumentor/phpdoc.inc | 45 + buildscripts/PhpDocumentor/phpdoc | 52 + buildscripts/PhpDocumentor/phpdoc.php | 469 ++ buildscripts/PhpDocumentor/poweredbyphpdoc.gif | Bin 0 -> 1363 bytes buildscripts/PhpDocumentor/scripts/add_cvs.php | 153 + .../PhpDocumentor/scripts/create_examples.php | 66 + .../PhpDocumentor/scripts/create_package.xml.php | 204 + buildscripts/PhpDocumentor/scripts/makedoc.sh | 94 + .../PhpDocumentor/scripts/tokenizer_test.php | 59 + buildscripts/PhpDocumentor/user/default.ini | 98 + buildscripts/PhpDocumentor/user/demo.ini | 78 + buildscripts/PhpDocumentor/user/error.ini | 82 + buildscripts/PhpDocumentor/user/pear-makedocs.ini | 71 + buildscripts/PhpDocumentor/user/prado.ini | 79 + buildscripts/PhpDocumentor/user/testdocbook.ini | 74 + buildscripts/index/api_index.php | 3 +- buildscripts/index/search.php | 36 + buildscripts/phing/CREDITS | 45 + buildscripts/phing/LICENSE | 1042 ++++ buildscripts/phing/README | 78 + buildscripts/phing/bin/pear-phing | 22 + buildscripts/phing/bin/pear-phing.bat | 44 + buildscripts/phing/bin/phing | 75 + buildscripts/phing/bin/phing.bat | 58 + buildscripts/phing/bin/phing.php | 50 + buildscripts/phing/classes/phing/BuildEvent.php | 205 + .../phing/classes/phing/BuildException.php | 100 + buildscripts/phing/classes/phing/BuildListener.php | 91 + .../phing/classes/phing/IntrospectionHelper.php | 542 ++ buildscripts/phing/classes/phing/Phing.php | 1161 +++++ buildscripts/phing/classes/phing/Project.php | 966 ++++ .../phing/classes/phing/ProjectComponent.php | 72 + .../phing/classes/phing/RuntimeConfigurable.php | 118 + buildscripts/phing/classes/phing/Target.php | 317 ++ buildscripts/phing/classes/phing/Task.php | 266 + buildscripts/phing/classes/phing/TaskAdapter.php | 84 + buildscripts/phing/classes/phing/TaskContainer.php | 42 + .../phing/classes/phing/UnknownElement.php | 211 + .../classes/phing/filters/BaseFilterReader.php | 157 + .../phing/filters/BaseParamFilterReader.php | 69 + .../classes/phing/filters/ChainableReader.php | 42 + .../classes/phing/filters/ExpandProperties.php | 82 + .../phing/classes/phing/filters/HeadFilter.php | 161 + .../phing/classes/phing/filters/LineContains.php | 258 + .../classes/phing/filters/LineContainsRegexp.php | 179 + .../phing/classes/phing/filters/PrefixLines.php | 142 + .../phing/classes/phing/filters/ReplaceRegexp.php | 129 + .../phing/classes/phing/filters/ReplaceTokens.php | 415 ++ .../classes/phing/filters/StripLineBreaks.php | 148 + .../classes/phing/filters/StripLineComments.php | 205 + .../classes/phing/filters/StripPhpComments.php | 190 + .../phing/classes/phing/filters/TabToSpaces.php | 144 + .../phing/classes/phing/filters/TailFilter.php | 157 + .../phing/classes/phing/filters/TidyFilter.php | 162 + .../classes/phing/filters/TranslateGettext.php | 285 + .../phing/classes/phing/filters/XsltFilter.php | 317 ++ .../phing/filters/util/ChainReaderHelper.php | 184 + .../phing/filters/util/IniFileTokenReader.php | 96 + .../classes/phing/input/DefaultInputHandler.php | 82 + .../phing/classes/phing/input/InputHandler.php | 45 + .../phing/classes/phing/input/InputRequest.php | 107 + .../phing/input/MultipleChoiceInputRequest.php | 58 + .../phing/input/PropertyFileInputHandler.php | 129 + .../classes/phing/input/YesNoInputRequest.php | 47 + buildscripts/phing/classes/phing/lib/Capsule.php | 266 + buildscripts/phing/classes/phing/lib/Zip.php | 3588 +++++++++++++ .../classes/phing/listener/AnsiColorLogger.php | 231 + .../phing/classes/phing/listener/BuildLogger.php | 42 + .../phing/classes/phing/listener/DefaultLogger.php | 233 + .../classes/phing/listener/NoBannerLogger.php | 61 + .../phing/classes/phing/listener/PearLogger.php | 246 + .../phing/classes/phing/listener/XmlLogger.php | 265 + .../classes/phing/listener/defaults.properties | 43 + .../phing/classes/phing/mappers/FileNameMapper.php | 59 + .../phing/classes/phing/mappers/FlattenMapper.php | 55 + .../phing/classes/phing/mappers/GlobMapper.php | 113 + .../phing/classes/phing/mappers/IdentityMapper.php | 54 + .../phing/classes/phing/mappers/MergeMapper.php | 69 + .../phing/classes/phing/mappers/RegexpMapper.php | 97 + .../phing/classes/phing/parser/AbstractHandler.php | 98 + .../classes/phing/parser/AbstractSAXParser.php | 140 + .../phing/classes/phing/parser/DataTypeHandler.php | 144 + .../classes/phing/parser/ExpatParseException.php | 31 + .../phing/classes/phing/parser/ExpatParser.php | 140 + .../phing/classes/phing/parser/Location.php | 72 + .../classes/phing/parser/NestedElementHandler.php | 186 + .../classes/phing/parser/ProjectConfigurator.php | 246 + .../phing/classes/phing/parser/ProjectHandler.php | 146 + .../phing/classes/phing/parser/RootHandler.php | 82 + .../phing/classes/phing/parser/TargetHandler.php | 149 + .../phing/classes/phing/parser/TaskHandler.php | 229 + .../classes/phing/system/io/BufferedReader.php | 170 + .../classes/phing/system/io/BufferedWriter.php | 72 + .../classes/phing/system/io/ConsoleReader.php | 84 + .../phing/classes/phing/system/io/FileReader.php | 179 + .../phing/classes/phing/system/io/FileSystem.php | 657 +++ .../phing/classes/phing/system/io/FileWriter.php | 139 + .../phing/classes/phing/system/io/FilterReader.php | 72 + .../phing/classes/phing/system/io/IOException.php | 28 + .../phing/classes/phing/system/io/PhingFile.php | 866 ++++ .../phing/classes/phing/system/io/Reader.php | 88 + .../phing/classes/phing/system/io/StringReader.php | 73 + .../phing/classes/phing/system/io/TokenReader.php | 51 + .../classes/phing/system/io/UnixFileSystem.php | 266 + .../classes/phing/system/io/Win32FileSystem.php | 477 ++ .../classes/phing/system/io/WinNTFileSystem.php | 35 + .../phing/classes/phing/system/io/Writer.php | 48 + .../phing/classes/phing/system/lang/Character.php | 49 + .../classes/phing/system/lang/EventObject.php | 52 + .../phing/system/lang/FileNotFoundException.php | 27 + .../phing/system/lang/NullPointerException.php | 27 + .../phing/system/lang/SecurityException.php | 27 + .../phing/classes/phing/system/util/Message.php | 9 + .../phing/classes/phing/system/util/Properties.php | 270 + .../phing/classes/phing/system/util/Register.php | 115 + .../phing/classes/phing/system/util/Timer.php | 96 + .../phing/classes/phing/tasks/defaults.properties | 69 + .../phing/classes/phing/tasks/ext/CapsuleTask.php | 478 ++ .../classes/phing/tasks/ext/CreoleSQLExecTask.php | 556 ++ .../phing/classes/phing/tasks/ext/CreoleTask.php | 242 + .../phing/classes/phing/tasks/ext/MailTask.php | 77 + .../classes/phing/tasks/ext/PackageAsPathTask.php | 65 + .../classes/phing/tasks/ext/PearPackageTask.php | 421 ++ .../phing/classes/phing/tasks/ext/PhpLintTask.php | 82 + .../phing/classes/phing/tasks/ext/SmartyTask.php | 610 +++ .../phing/classes/phing/tasks/ext/TarTask.php | 380 ++ .../phing/classes/phing/tasks/ext/XmlLintTask.php | 116 + .../phing/tasks/ext/ZendCodeAnalyzerTask.php | 163 + .../phing/classes/phing/tasks/ext/ZipTask.php | 176 + .../phing/tasks/ext/coverage/CoverageMerger.php | 127 + .../tasks/ext/coverage/CoverageMergerTask.php | 92 + .../tasks/ext/coverage/CoverageReportTask.php | 406 ++ .../ext/coverage/CoverageReportTransformer.php | 121 + .../phing/tasks/ext/coverage/CoverageSetupTask.php | 163 + .../phing/tasks/ext/ioncube/IoncubeComment.php | 44 + .../phing/tasks/ext/ioncube/IoncubeEncoderTask.php | 336 ++ .../phing/tasks/ext/ioncube/IoncubeLicenseTask.php | 144 + .../phing/tasks/ext/pearpackage/Fileset.php | 231 + .../phing/tasks/ext/phpdoc/PHPDocumentorTask.php | 157 + .../classes/phing/tasks/ext/phpunit2/BatchTest.php | 171 + .../phing/tasks/ext/phpunit2/FormatterElement.php | 120 + .../tasks/ext/phpunit2/PHPUnit2ReportTask.php | 162 + .../tasks/ext/phpunit2/PHPUnit2ResultFormatter.php | 154 + .../phing/tasks/ext/phpunit2/PHPUnit2Task.php | 239 + .../tasks/ext/phpunit2/PHPUnit2TestRunner.php | 107 + .../phing/tasks/ext/phpunit2/PHPUnit2Util.php | 114 + .../ext/phpunit2/PlainPHPUnit2ResultFormatter.php | 117 + .../phpunit2/SummaryPHPUnit2ResultFormatter.php | 58 + .../ext/phpunit2/XMLPHPUnit2ResultFormatter.php | 117 + .../simpletest/SimpleTestCountResultFormatter.php | 52 + .../ext/simpletest/SimpleTestFormatterElement.php | 62 + .../simpletest/SimpleTestPlainResultFormatter.php | 95 + .../ext/simpletest/SimpleTestResultFormatter.php | 162 + .../SimpleTestSummaryResultFormatter.php | 54 + .../phing/tasks/ext/simpletest/SimpleTestTask.php | 238 + .../classes/phing/tasks/ext/svn/SvnBaseTask.php | 180 + .../classes/phing/tasks/ext/svn/SvnExportTask.php | 68 + .../phing/tasks/ext/svn/SvnLastRevisionTask.php | 75 + .../phing/classes/phing/tasks/system/AdhocTask.php | 88 + .../phing/tasks/system/AdhocTaskdefTask.php | 90 + .../phing/tasks/system/AdhocTypedefTask.php | 71 + .../classes/phing/tasks/system/AppendTask.php | 240 + .../classes/phing/tasks/system/AvailableTask.php | 132 + .../phing/classes/phing/tasks/system/ChmodTask.php | 177 + .../classes/phing/tasks/system/ConditionTask.php | 74 + .../phing/classes/phing/tasks/system/CopyTask.php | 401 ++ .../classes/phing/tasks/system/CvsPassTask.php | 173 + .../phing/classes/phing/tasks/system/CvsTask.php | 540 ++ .../classes/phing/tasks/system/DeleteTask.php | 277 + .../phing/classes/phing/tasks/system/EchoTask.php | 107 + .../phing/classes/phing/tasks/system/ExecTask.php | 248 + .../phing/classes/phing/tasks/system/ExitTask.php | 118 + .../classes/phing/tasks/system/ForeachTask.php | 138 + .../phing/classes/phing/tasks/system/IfTask.php | 224 + .../classes/phing/tasks/system/IncludePathTask.php | 115 + .../phing/classes/phing/tasks/system/InputTask.php | 146 + .../classes/phing/tasks/system/MatchingTask.php | 361 ++ .../phing/classes/phing/tasks/system/MkdirTask.php | 64 + .../phing/classes/phing/tasks/system/MoveTask.php | 197 + .../classes/phing/tasks/system/PhingCallTask.php | 139 + .../phing/classes/phing/tasks/system/PhingTask.php | 596 +++ .../classes/phing/tasks/system/PhpEvalTask.php | 169 + .../phing/tasks/system/PropertyPromptTask.php | 201 + .../classes/phing/tasks/system/PropertyTask.php | 438 ++ .../classes/phing/tasks/system/ReflexiveTask.php | 155 + .../classes/phing/tasks/system/ResolvePathTask.php | 122 + .../classes/phing/tasks/system/SequentialTask.php | 57 + .../classes/phing/tasks/system/TaskdefTask.php | 127 + .../phing/classes/phing/tasks/system/TouchTask.php | 170 + .../classes/phing/tasks/system/TstampTask.php | 168 + .../classes/phing/tasks/system/TypedefTask.php | 125 + .../classes/phing/tasks/system/UpToDateTask.php | 217 + .../phing/classes/phing/tasks/system/WarnTask.php | 35 + .../phing/classes/phing/tasks/system/XsltTask.php | 81 + .../phing/tasks/system/condition/AndCondition.php | 46 + .../phing/tasks/system/condition/Condition.php | 39 + .../phing/tasks/system/condition/ConditionBase.php | 195 + .../tasks/system/condition/ContainsCondition.php | 76 + .../tasks/system/condition/EqualsCondition.php | 78 + .../tasks/system/condition/IsFalseCondition.php | 60 + .../tasks/system/condition/IsSetCondition.php | 53 + .../tasks/system/condition/IsTrueCondition.php | 59 + .../phing/tasks/system/condition/NotCondition.php | 48 + .../phing/tasks/system/condition/OrCondition.php | 46 + .../phing/tasks/system/condition/OsCondition.php | 63 + .../system/condition/ReferenceExistsCondition.php | 52 + .../phing/classes/phing/types/AbstractFileSet.php | 570 ++ .../phing/classes/phing/types/Commandline.php | 467 ++ .../phing/classes/phing/types/DataType.php | 182 + .../phing/classes/phing/types/Description.php | 53 + buildscripts/phing/classes/phing/types/DirSet.php | 49 + .../phing/classes/phing/types/FileList.php | 223 + buildscripts/phing/classes/phing/types/FileSet.php | 56 + .../phing/classes/phing/types/FilterChain.php | 164 + buildscripts/phing/classes/phing/types/Mapper.php | 207 + .../phing/classes/phing/types/Parameter.php | 99 + .../phing/classes/phing/types/Parameterizable.php | 32 + buildscripts/phing/classes/phing/types/Path.php | 456 ++ .../phing/classes/phing/types/PatternSet.php | 449 ++ .../classes/phing/types/PhingFilterReader.php | 136 + .../phing/classes/phing/types/Reference.php | 56 + .../classes/phing/types/RegularExpression.php | 105 + .../phing/classes/phing/types/TokenReader.php | 66 + .../phing/classes/phing/types/TokenSource.php | 157 + .../phing/classes/phing/types/defaults.properties | 13 + .../classes/phing/types/selectors/AndSelector.php | 67 + .../phing/types/selectors/BaseExtendSelector.php | 62 + .../classes/phing/types/selectors/BaseSelector.php | 84 + .../types/selectors/BaseSelectorContainer.php | 270 + .../types/selectors/ContainsRegexpSelector.php | 164 + .../phing/types/selectors/ContainsSelector.php | 151 + .../classes/phing/types/selectors/DateSelector.php | 214 + .../phing/types/selectors/DependSelector.php | 151 + .../phing/types/selectors/DepthSelector.php | 158 + .../phing/types/selectors/ExtendFileSelector.php | 43 + .../phing/types/selectors/ExtendSelector.php | 127 + .../classes/phing/types/selectors/FileSelector.php | 47 + .../phing/types/selectors/FilenameSelector.php | 157 + .../phing/types/selectors/MajoritySelector.php | 92 + .../classes/phing/types/selectors/NoneSelector.php | 71 + .../classes/phing/types/selectors/NotSelector.php | 59 + .../classes/phing/types/selectors/OrSelector.php | 72 + .../phing/types/selectors/PresentSelector.php | 154 + .../phing/types/selectors/SelectSelector.php | 124 + .../phing/types/selectors/SelectorContainer.php | 141 + .../phing/types/selectors/SelectorScanner.php | 55 + .../phing/types/selectors/SelectorUtils.php | 440 ++ .../classes/phing/types/selectors/SizeSelector.php | 228 + .../classes/phing/types/selectors/TypeSelector.php | 113 + .../phing/classes/phing/util/DirectoryScanner.php | 710 +++ .../classes/phing/util/ExtendedFileStream.php | 133 + .../phing/classes/phing/util/FileUtils.php | 294 ++ .../phing/classes/phing/util/LogWriter.php | 96 + .../phing/classes/phing/util/PathTokenizer.php | 245 + .../phing/classes/phing/util/SourceFileScanner.php | 159 + .../phing/classes/phing/util/StringHelper.php | 209 + .../phing/classes/phing/util/regexp/PregEngine.php | 105 + .../phing/classes/phing/util/regexp/Regexp.php | 168 + .../classes/phing/util/regexp/RegexpEngine.php | 74 + buildscripts/phing/etc/VERSION.TXT | 1 + buildscripts/phing/etc/coverage-frames.xsl | 669 +++ buildscripts/phing/etc/log.xsl | 216 + buildscripts/phing/etc/phpunit2-frames.xsl | 677 +++ buildscripts/phing/etc/phpunit2-noframes.xsl | 436 ++ buildscripts/phing/etc/str.replace.function.xsl | 105 + .../phing/pear/BuildPhingPEARPackageTask.php | 270 + buildscripts/phing/pear/build.xml | 156 + buildscripts/phing/tasks/ManualIndexTask.php | 38 + buildscripts/phing/tasks/PradoDocTask.php | 137 + buildscripts/phing/tasks/PradoPearTask.php | 133 + buildscripts/phing/tasks/PradoTestTask.php | 18 + buildscripts/phing/tasks/PradoVersionTask.php | 56 + buildscripts/phing/tasks/QuickstartIndexTask.php | 32 + buildscripts/texbuilder/quickstart.tex | 4 +- 565 files changed, 117130 insertions(+), 3 deletions(-) create mode 100644 buildscripts/Benchmark/Iterate.php create mode 100644 buildscripts/Benchmark/LICENSE create mode 100644 buildscripts/Benchmark/Profiler.php create mode 100644 buildscripts/Benchmark/Timer.php create mode 100644 buildscripts/Benchmark/doc/timer_example.php create mode 100644 buildscripts/PHPUnit2/Extensions/ExceptionTestCase.php create mode 100644 buildscripts/PHPUnit2/Extensions/PerformanceTestCase.php create mode 100644 buildscripts/PHPUnit2/Extensions/RepeatedTest.php create mode 100644 buildscripts/PHPUnit2/Extensions/TestDecorator.php create mode 100644 buildscripts/PHPUnit2/Extensions/TestSetup.php create mode 100644 buildscripts/PHPUnit2/Framework/Assert.php create mode 100644 buildscripts/PHPUnit2/Framework/AssertionFailedError.php create mode 100644 buildscripts/PHPUnit2/Framework/ComparisonFailure.php create mode 100644 buildscripts/PHPUnit2/Framework/Error.php create mode 100644 buildscripts/PHPUnit2/Framework/IncompleteTest.php create mode 100644 buildscripts/PHPUnit2/Framework/IncompleteTestError.php create mode 100644 buildscripts/PHPUnit2/Framework/Test.php create mode 100644 buildscripts/PHPUnit2/Framework/TestCase.php create mode 100644 buildscripts/PHPUnit2/Framework/TestFailure.php create mode 100644 buildscripts/PHPUnit2/Framework/TestListener.php create mode 100644 buildscripts/PHPUnit2/Framework/TestResult.php create mode 100644 buildscripts/PHPUnit2/Framework/TestSuite.php create mode 100644 buildscripts/PHPUnit2/Framework/Warning.php create mode 100644 buildscripts/PHPUnit2/Runner/BaseTestRunner.php create mode 100644 buildscripts/PHPUnit2/Runner/IncludePathTestCollector.php create mode 100644 buildscripts/PHPUnit2/Runner/StandardTestSuiteLoader.php create mode 100644 buildscripts/PHPUnit2/Runner/TestCollector.php create mode 100644 buildscripts/PHPUnit2/Runner/TestSuiteLoader.php create mode 100644 buildscripts/PHPUnit2/Runner/Version.php create mode 100644 buildscripts/PHPUnit2/TextUI/ResultPrinter.php create mode 100644 buildscripts/PHPUnit2/TextUI/TestRunner.php create mode 100644 buildscripts/PHPUnit2/Util/CodeCoverage/Renderer.php create mode 100644 buildscripts/PHPUnit2/Util/CodeCoverage/Renderer/HTML.php create mode 100644 buildscripts/PHPUnit2/Util/CodeCoverage/Renderer/Text.php create mode 100644 buildscripts/PHPUnit2/Util/ErrorHandler.php create mode 100644 buildscripts/PHPUnit2/Util/Fileloader.php create mode 100644 buildscripts/PHPUnit2/Util/Filter.php create mode 100644 buildscripts/PHPUnit2/Util/Log/PEAR.php create mode 100644 buildscripts/PHPUnit2/Util/Log/XML.php create mode 100644 buildscripts/PHPUnit2/Util/Printer.php create mode 100644 buildscripts/PHPUnit2/Util/Skeleton.php create mode 100644 buildscripts/PHPUnit2/Util/TestDox/NamePrettifier.php create mode 100644 buildscripts/PHPUnit2/Util/TestDox/ResultPrinter.php create mode 100644 buildscripts/PHPUnit2/Util/TestDox/ResultPrinter/HTML.php create mode 100644 buildscripts/PHPUnit2/Util/TestDox/ResultPrinter/Text.php create mode 100644 buildscripts/PHPUnit2/pear-phpunit create mode 100644 buildscripts/PHPUnit2/pear-phpunit.bat create mode 100644 buildscripts/PhpDocumentor/PHPLICENSE.txt create mode 100644 buildscripts/PhpDocumentor/new_phpdoc.php create mode 100644 buildscripts/PhpDocumentor/pear-phpdoc create mode 100644 buildscripts/PhpDocumentor/pear-phpdoc.bat create mode 100644 buildscripts/PhpDocumentor/phpDocumentor.ini create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Classes.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converter.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/CHMdefaultConverter.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/options.ini create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/basicindex.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/blank.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/class.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/classleft.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/classtrees.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/const.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/contents.hhc.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/define.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/docblock.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/elementindex.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/errors.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/fileleft.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/filesource.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/footer.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/function.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/global.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/header.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/hhp.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/include.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/index.hhk.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/index.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/media/bg_left.png create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/media/stylesheet.css create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/method.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/packages.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/page.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/pkgelementindex.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/ric.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/tocentry.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/todolist.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/tutorial.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/tutorial_toc.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/tutorial_tree.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/var.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/HTMLSmartyConverter.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/options.ini create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/__tags.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_class_declaration.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_class_description.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_class_list.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_constant_details.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_constant_summary.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_constructor_details.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_constructor_summary.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_destructor_details.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_destructor_summary.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_footer.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_get_constant_type.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_header.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_inherited_constants.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_inherited_methods.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_inheritence_tree.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_method_details.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_method_summary.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_sub_classes.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_tags.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/basicindex.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/blank.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/class.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/classleft.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/classtrees.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/const.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/define.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/docblock.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/elementindex.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/errors.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/examplesource.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/fileleft.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/filesource.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/footer.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/function.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/global.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/header.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/include.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/index.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/media/background.png create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/media/empty.png create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/media/style.css create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/method.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/packages.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/page.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/pkgelementindex.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/ric.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/todolist.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/tutorial.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/tutorial_toc.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/tutorial_tree.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/var.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/HTMLframesConverter.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/options.ini create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/basicindex.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/blank.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/class.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/classtrees.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/const.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/define.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/docblock.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/elementindex.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/errors.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/examplesource.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/filesource.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/footer.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/function.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/global.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/header.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/include.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/index.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/left_frame.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/media/banner.css create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/media/stylesheet.css create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/method.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/page.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/pkgelementindex.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/ric.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/todolist.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/top_frame.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/tutorial.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/tutorial_nav.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/tutorial_toc.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/tutorial_tree.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/var.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/DescHTML.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/DocBlock/Lexer.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/DocBlockTags.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Errors.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/EventStack.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/HighlightParser.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/InlineTags.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/IntermediateParser.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Io.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/LinkClasses.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/PackagePageElements.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Parser.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/ParserData.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/ParserDescCleanup.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/ParserDocBlock.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/ParserElements.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/ProceduralPages.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Publisher.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Setup.inc.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/BUGS create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/COPYING.lib create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/ChangeLog create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/FAQ create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/INSTALL create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/NEWS create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/README create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/RELEASE_NOTES create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/TODO create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/Config_File.class.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/Smarty.class.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/Smarty_Compiler.class.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.assemble_plugin_filepath.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.assign_smarty_interface.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.create_dir_structure.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.display_debug_console.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.get_include_path.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.get_microtime.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.get_php_resource.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.is_secure.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.is_trusted.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.load_plugins.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.load_resource_plugin.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.process_cached_inserts.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.process_compiled_include.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.read_cache_file.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.rm_auto.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.rmdir.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.run_insert_handler.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.smarty_include_php.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.write_cache_file.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.write_compiled_include.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.write_compiled_resource.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/core/core.write_file.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/debug.tpl create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/block.strip.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/block.textformat.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.assign.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.assign_debug_info.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.config_load.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.counter.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.cycle.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.debug.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.eval.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.fetch.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_checkboxes.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_image.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_options.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_radios.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_select_date.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_select_time.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_table.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.mailto.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.math.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.popup.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.popup_init.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.var_dump.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.capitalize.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.cat.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.count_characters.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.count_paragraphs.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.count_sentences.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.count_words.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.date_format.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.debug_print_var.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.default.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.escape.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.htmlentities.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.indent.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.lower.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.nl2br.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.rawurlencode.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.regex_replace.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.replace.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.spacify.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.string_format.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.strip.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.strip_tags.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.truncate.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.upper.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.wordwrap.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/outputfilter.trimwhitespace.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/shared.escape_special_chars.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/shared.make_timestamp.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/misc/smarty_icon.README create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/misc/smarty_icon.gif create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/TutorialHighlightParser.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/WordParser.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/XMLpackagePageParser.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/clone.inc.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/clone5.inc.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/common.inc.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/find_phpdoc.php create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/phpDocumentorTParser.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/phpDocumentorTWordParser.inc create mode 100644 buildscripts/PhpDocumentor/phpDocumentor/phpdoc.inc create mode 100644 buildscripts/PhpDocumentor/phpdoc create mode 100644 buildscripts/PhpDocumentor/phpdoc.php create mode 100644 buildscripts/PhpDocumentor/poweredbyphpdoc.gif create mode 100644 buildscripts/PhpDocumentor/scripts/add_cvs.php create mode 100644 buildscripts/PhpDocumentor/scripts/create_examples.php create mode 100644 buildscripts/PhpDocumentor/scripts/create_package.xml.php create mode 100644 buildscripts/PhpDocumentor/scripts/makedoc.sh create mode 100644 buildscripts/PhpDocumentor/scripts/tokenizer_test.php create mode 100644 buildscripts/PhpDocumentor/user/default.ini create mode 100644 buildscripts/PhpDocumentor/user/demo.ini create mode 100644 buildscripts/PhpDocumentor/user/error.ini create mode 100644 buildscripts/PhpDocumentor/user/pear-makedocs.ini create mode 100644 buildscripts/PhpDocumentor/user/prado.ini create mode 100644 buildscripts/PhpDocumentor/user/testdocbook.ini create mode 100644 buildscripts/index/search.php create mode 100644 buildscripts/phing/CREDITS create mode 100644 buildscripts/phing/LICENSE create mode 100644 buildscripts/phing/README create mode 100644 buildscripts/phing/bin/pear-phing create mode 100644 buildscripts/phing/bin/pear-phing.bat create mode 100644 buildscripts/phing/bin/phing create mode 100644 buildscripts/phing/bin/phing.bat create mode 100644 buildscripts/phing/bin/phing.php create mode 100644 buildscripts/phing/classes/phing/BuildEvent.php create mode 100644 buildscripts/phing/classes/phing/BuildException.php create mode 100644 buildscripts/phing/classes/phing/BuildListener.php create mode 100644 buildscripts/phing/classes/phing/IntrospectionHelper.php create mode 100644 buildscripts/phing/classes/phing/Phing.php create mode 100644 buildscripts/phing/classes/phing/Project.php create mode 100644 buildscripts/phing/classes/phing/ProjectComponent.php create mode 100644 buildscripts/phing/classes/phing/RuntimeConfigurable.php create mode 100644 buildscripts/phing/classes/phing/Target.php create mode 100644 buildscripts/phing/classes/phing/Task.php create mode 100644 buildscripts/phing/classes/phing/TaskAdapter.php create mode 100644 buildscripts/phing/classes/phing/TaskContainer.php create mode 100644 buildscripts/phing/classes/phing/UnknownElement.php create mode 100644 buildscripts/phing/classes/phing/filters/BaseFilterReader.php create mode 100644 buildscripts/phing/classes/phing/filters/BaseParamFilterReader.php create mode 100644 buildscripts/phing/classes/phing/filters/ChainableReader.php create mode 100644 buildscripts/phing/classes/phing/filters/ExpandProperties.php create mode 100644 buildscripts/phing/classes/phing/filters/HeadFilter.php create mode 100644 buildscripts/phing/classes/phing/filters/LineContains.php create mode 100644 buildscripts/phing/classes/phing/filters/LineContainsRegexp.php create mode 100644 buildscripts/phing/classes/phing/filters/PrefixLines.php create mode 100644 buildscripts/phing/classes/phing/filters/ReplaceRegexp.php create mode 100644 buildscripts/phing/classes/phing/filters/ReplaceTokens.php create mode 100644 buildscripts/phing/classes/phing/filters/StripLineBreaks.php create mode 100644 buildscripts/phing/classes/phing/filters/StripLineComments.php create mode 100644 buildscripts/phing/classes/phing/filters/StripPhpComments.php create mode 100644 buildscripts/phing/classes/phing/filters/TabToSpaces.php create mode 100644 buildscripts/phing/classes/phing/filters/TailFilter.php create mode 100644 buildscripts/phing/classes/phing/filters/TidyFilter.php create mode 100644 buildscripts/phing/classes/phing/filters/TranslateGettext.php create mode 100644 buildscripts/phing/classes/phing/filters/XsltFilter.php create mode 100644 buildscripts/phing/classes/phing/filters/util/ChainReaderHelper.php create mode 100644 buildscripts/phing/classes/phing/filters/util/IniFileTokenReader.php create mode 100644 buildscripts/phing/classes/phing/input/DefaultInputHandler.php create mode 100644 buildscripts/phing/classes/phing/input/InputHandler.php create mode 100644 buildscripts/phing/classes/phing/input/InputRequest.php create mode 100644 buildscripts/phing/classes/phing/input/MultipleChoiceInputRequest.php create mode 100644 buildscripts/phing/classes/phing/input/PropertyFileInputHandler.php create mode 100644 buildscripts/phing/classes/phing/input/YesNoInputRequest.php create mode 100644 buildscripts/phing/classes/phing/lib/Capsule.php create mode 100644 buildscripts/phing/classes/phing/lib/Zip.php create mode 100644 buildscripts/phing/classes/phing/listener/AnsiColorLogger.php create mode 100644 buildscripts/phing/classes/phing/listener/BuildLogger.php create mode 100644 buildscripts/phing/classes/phing/listener/DefaultLogger.php create mode 100644 buildscripts/phing/classes/phing/listener/NoBannerLogger.php create mode 100644 buildscripts/phing/classes/phing/listener/PearLogger.php create mode 100644 buildscripts/phing/classes/phing/listener/XmlLogger.php create mode 100644 buildscripts/phing/classes/phing/listener/defaults.properties create mode 100644 buildscripts/phing/classes/phing/mappers/FileNameMapper.php create mode 100644 buildscripts/phing/classes/phing/mappers/FlattenMapper.php create mode 100644 buildscripts/phing/classes/phing/mappers/GlobMapper.php create mode 100644 buildscripts/phing/classes/phing/mappers/IdentityMapper.php create mode 100644 buildscripts/phing/classes/phing/mappers/MergeMapper.php create mode 100644 buildscripts/phing/classes/phing/mappers/RegexpMapper.php create mode 100644 buildscripts/phing/classes/phing/parser/AbstractHandler.php create mode 100644 buildscripts/phing/classes/phing/parser/AbstractSAXParser.php create mode 100644 buildscripts/phing/classes/phing/parser/DataTypeHandler.php create mode 100644 buildscripts/phing/classes/phing/parser/ExpatParseException.php create mode 100644 buildscripts/phing/classes/phing/parser/ExpatParser.php create mode 100644 buildscripts/phing/classes/phing/parser/Location.php create mode 100644 buildscripts/phing/classes/phing/parser/NestedElementHandler.php create mode 100644 buildscripts/phing/classes/phing/parser/ProjectConfigurator.php create mode 100644 buildscripts/phing/classes/phing/parser/ProjectHandler.php create mode 100644 buildscripts/phing/classes/phing/parser/RootHandler.php create mode 100644 buildscripts/phing/classes/phing/parser/TargetHandler.php create mode 100644 buildscripts/phing/classes/phing/parser/TaskHandler.php create mode 100644 buildscripts/phing/classes/phing/system/io/BufferedReader.php create mode 100644 buildscripts/phing/classes/phing/system/io/BufferedWriter.php create mode 100644 buildscripts/phing/classes/phing/system/io/ConsoleReader.php create mode 100644 buildscripts/phing/classes/phing/system/io/FileReader.php create mode 100644 buildscripts/phing/classes/phing/system/io/FileSystem.php create mode 100644 buildscripts/phing/classes/phing/system/io/FileWriter.php create mode 100644 buildscripts/phing/classes/phing/system/io/FilterReader.php create mode 100644 buildscripts/phing/classes/phing/system/io/IOException.php create mode 100644 buildscripts/phing/classes/phing/system/io/PhingFile.php create mode 100644 buildscripts/phing/classes/phing/system/io/Reader.php create mode 100644 buildscripts/phing/classes/phing/system/io/StringReader.php create mode 100644 buildscripts/phing/classes/phing/system/io/TokenReader.php create mode 100644 buildscripts/phing/classes/phing/system/io/UnixFileSystem.php create mode 100644 buildscripts/phing/classes/phing/system/io/Win32FileSystem.php create mode 100644 buildscripts/phing/classes/phing/system/io/WinNTFileSystem.php create mode 100644 buildscripts/phing/classes/phing/system/io/Writer.php create mode 100644 buildscripts/phing/classes/phing/system/lang/Character.php create mode 100644 buildscripts/phing/classes/phing/system/lang/EventObject.php create mode 100644 buildscripts/phing/classes/phing/system/lang/FileNotFoundException.php create mode 100644 buildscripts/phing/classes/phing/system/lang/NullPointerException.php create mode 100644 buildscripts/phing/classes/phing/system/lang/SecurityException.php create mode 100644 buildscripts/phing/classes/phing/system/util/Message.php create mode 100644 buildscripts/phing/classes/phing/system/util/Properties.php create mode 100644 buildscripts/phing/classes/phing/system/util/Register.php create mode 100644 buildscripts/phing/classes/phing/system/util/Timer.php create mode 100644 buildscripts/phing/classes/phing/tasks/defaults.properties create mode 100644 buildscripts/phing/classes/phing/tasks/ext/CapsuleTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/CreoleSQLExecTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/CreoleTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/MailTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/PackageAsPathTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/PearPackageTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/PhpLintTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/SmartyTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/TarTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/XmlLintTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/ZendCodeAnalyzerTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/ZipTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMerger.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMergerTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTransformer.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageSetupTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeComment.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeEncoderTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeLicenseTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/pearpackage/Fileset.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpdoc/PHPDocumentorTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/BatchTest.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/FormatterElement.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2ReportTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2ResultFormatter.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2Task.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2TestRunner.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2Util.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/PlainPHPUnit2ResultFormatter.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/SummaryPHPUnit2ResultFormatter.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/XMLPHPUnit2ResultFormatter.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestCountResultFormatter.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestFormatterElement.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestPlainResultFormatter.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestResultFormatter.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestSummaryResultFormatter.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/svn/SvnBaseTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/svn/SvnExportTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/svn/SvnLastRevisionTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/AdhocTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/AdhocTaskdefTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/AdhocTypedefTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/AppendTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/AvailableTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/ChmodTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/ConditionTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/CopyTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/CvsPassTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/CvsTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/DeleteTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/EchoTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/ExecTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/ExitTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/ForeachTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/IfTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/IncludePathTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/InputTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/MatchingTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/MkdirTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/MoveTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/PhingCallTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/PhingTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/PhpEvalTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/PropertyPromptTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/PropertyTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/ReflexiveTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/ResolvePathTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/SequentialTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/TaskdefTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/TouchTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/TstampTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/TypedefTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/UpToDateTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/WarnTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/XsltTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/condition/AndCondition.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/condition/Condition.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/condition/ConditionBase.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/condition/ContainsCondition.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/condition/EqualsCondition.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/condition/IsFalseCondition.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/condition/IsSetCondition.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/condition/IsTrueCondition.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/condition/NotCondition.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/condition/OrCondition.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/condition/OsCondition.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/condition/ReferenceExistsCondition.php create mode 100644 buildscripts/phing/classes/phing/types/AbstractFileSet.php create mode 100644 buildscripts/phing/classes/phing/types/Commandline.php create mode 100644 buildscripts/phing/classes/phing/types/DataType.php create mode 100644 buildscripts/phing/classes/phing/types/Description.php create mode 100644 buildscripts/phing/classes/phing/types/DirSet.php create mode 100644 buildscripts/phing/classes/phing/types/FileList.php create mode 100644 buildscripts/phing/classes/phing/types/FileSet.php create mode 100644 buildscripts/phing/classes/phing/types/FilterChain.php create mode 100644 buildscripts/phing/classes/phing/types/Mapper.php create mode 100644 buildscripts/phing/classes/phing/types/Parameter.php create mode 100644 buildscripts/phing/classes/phing/types/Parameterizable.php create mode 100644 buildscripts/phing/classes/phing/types/Path.php create mode 100644 buildscripts/phing/classes/phing/types/PatternSet.php create mode 100644 buildscripts/phing/classes/phing/types/PhingFilterReader.php create mode 100644 buildscripts/phing/classes/phing/types/Reference.php create mode 100644 buildscripts/phing/classes/phing/types/RegularExpression.php create mode 100644 buildscripts/phing/classes/phing/types/TokenReader.php create mode 100644 buildscripts/phing/classes/phing/types/TokenSource.php create mode 100644 buildscripts/phing/classes/phing/types/defaults.properties create mode 100644 buildscripts/phing/classes/phing/types/selectors/AndSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/BaseExtendSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/BaseSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/BaseSelectorContainer.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/ContainsRegexpSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/ContainsSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/DateSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/DependSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/DepthSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/ExtendFileSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/ExtendSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/FileSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/FilenameSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/MajoritySelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/NoneSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/NotSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/OrSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/PresentSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/SelectSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/SelectorContainer.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/SelectorScanner.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/SelectorUtils.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/SizeSelector.php create mode 100644 buildscripts/phing/classes/phing/types/selectors/TypeSelector.php create mode 100644 buildscripts/phing/classes/phing/util/DirectoryScanner.php create mode 100644 buildscripts/phing/classes/phing/util/ExtendedFileStream.php create mode 100644 buildscripts/phing/classes/phing/util/FileUtils.php create mode 100644 buildscripts/phing/classes/phing/util/LogWriter.php create mode 100644 buildscripts/phing/classes/phing/util/PathTokenizer.php create mode 100644 buildscripts/phing/classes/phing/util/SourceFileScanner.php create mode 100644 buildscripts/phing/classes/phing/util/StringHelper.php create mode 100644 buildscripts/phing/classes/phing/util/regexp/PregEngine.php create mode 100644 buildscripts/phing/classes/phing/util/regexp/Regexp.php create mode 100644 buildscripts/phing/classes/phing/util/regexp/RegexpEngine.php create mode 100644 buildscripts/phing/etc/VERSION.TXT create mode 100644 buildscripts/phing/etc/coverage-frames.xsl create mode 100644 buildscripts/phing/etc/log.xsl create mode 100644 buildscripts/phing/etc/phpunit2-frames.xsl create mode 100644 buildscripts/phing/etc/phpunit2-noframes.xsl create mode 100644 buildscripts/phing/etc/str.replace.function.xsl create mode 100644 buildscripts/phing/pear/BuildPhingPEARPackageTask.php create mode 100644 buildscripts/phing/pear/build.xml create mode 100644 buildscripts/phing/tasks/ManualIndexTask.php create mode 100644 buildscripts/phing/tasks/PradoDocTask.php create mode 100644 buildscripts/phing/tasks/PradoPearTask.php create mode 100644 buildscripts/phing/tasks/PradoTestTask.php create mode 100644 buildscripts/phing/tasks/PradoVersionTask.php create mode 100644 buildscripts/phing/tasks/QuickstartIndexTask.php (limited to 'buildscripts') diff --git a/buildscripts/Benchmark/Iterate.php b/buildscripts/Benchmark/Iterate.php new file mode 100644 index 00000000..acf1ec08 --- /dev/null +++ b/buildscripts/Benchmark/Iterate.php @@ -0,0 +1,167 @@ +. | +// +------------------------------------------------------------------------+ +// | This source file is subject to the New BSD license, That is bundled | +// | with this package in the file LICENSE, and is available through | +// | the world-wide-web at | +// | http://www.opensource.org/licenses/bsd-license.php | +// | If you did not receive a copy of the new BSDlicense and are unable | +// | to obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +------------------------------------------------------------------------+ +// +// $Id: Iterate.php,v 1.12 2006/02/17 16:29:44 toggg Exp $ +// + +require_once 'Benchmark/Timer.php'; + +/** + * Provides timing and profiling information. + * + * Example 1 + * + * + * '; + * } + * + * $benchmark->run(100, 'foo', 'test'); + * $result = $benchmark->get(); + * ?> + * + * + * Example 2 + * + * + * '; + * } + * } + * + * $benchmark->run(100, 'myclass::foo', 'test'); + * $result = $benchmark->get(); + * ?> + * + * + * Example 3 + * + * + * '; + * } + * } + * + * $o = new MyClass(); + * + * $benchmark->run(100, 'o->foo', 'test'); + * $result = $benchmark->get(); + * ?> + * + * + * @author Sebastian Bergmann + * @copyright Copyright © 2002-2005 Sebastian Bergmann + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 + * @category Benchmarking + * @package Benchmark + */ +class Benchmark_Iterate extends Benchmark_Timer { + /** + * Benchmarks a function or method. + * + * @access public + */ + function run() { + $arguments = func_get_args(); + $iterations = array_shift($arguments); + $function_name = array_shift($arguments); + + if (strstr($function_name, '::')) { + $function_name = explode('::', $function_name); + $objectmethod = $function_name[1]; + } + + if (strstr($function_name, '->')) { + $function_name = explode('->', $function_name); + $objectname = $function_name[0]; + + $object = $GLOBALS[$objectname]; + $objectmethod = $function_name[1]; + + for ($i = 1; $i <= $iterations; $i++) { + $this->setMarker('start_' . $i); + call_user_func_array(array($object, $function_name[1]), $arguments); + $this->setMarker('end_' . $i); + } + + return(0); + } + + for ($i = 1; $i <= $iterations; $i++) { + $this->setMarker('start_' . $i); + call_user_func_array($function_name, $arguments); + $this->setMarker('end_' . $i); + } + } + + /** + * Returns benchmark result. + * + * $result[x ] = execution time of iteration x + * $result['mean' ] = mean execution time + * $result['iterations'] = number of iterations + * + * @return array + * @access public + */ + function get($simple_output = false) { + $result = array(); + $total = 0; + + $iterations = count($this->markers)/2; + + for ($i = 1; $i <= $iterations; $i++) { + $time = $this->timeElapsed('start_'.$i , 'end_'.$i); + + if (extension_loaded('bcmath')) { + $total = bcadd($total, $time, 6); + } else { + $total = $total + $time; + } + + if (!$simple_output) { + $result[$i] = $time; + } + } + + if (extension_loaded('bcmath')) { + $result['mean'] = bcdiv($total, $iterations, 6); + } else { + $result['mean'] = $total / $iterations; + } + + $result['iterations'] = $iterations; + + return $result; + } +} diff --git a/buildscripts/Benchmark/LICENSE b/buildscripts/Benchmark/LICENSE new file mode 100644 index 00000000..db25e880 --- /dev/null +++ b/buildscripts/Benchmark/LICENSE @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without modification +, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, th + is list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation and/ + or other materials provided with the distribution. + +3. The name of the author may not be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WA +RRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABIL +ITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR C +ONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOW +EVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILI +TY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE U +SE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/buildscripts/Benchmark/Profiler.php b/buildscripts/Benchmark/Profiler.php new file mode 100644 index 00000000..e9108a84 --- /dev/null +++ b/buildscripts/Benchmark/Profiler.php @@ -0,0 +1,447 @@ +. | +// +----------------------------------------------------------------------+ +// | This source file is subject to the New BSD license, That is bundled | +// | with this package in the file LICENSE, and is available through | +// | the world-wide-web at | +// | http://www.opensource.org/licenses/bsd-license.php | +// | If you did not receive a copy of the new BSDlicense and are unable | +// | to obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +----------------------------------------------------------------------+ +// +// $Id: Profiler.php,v 1.19 2006/03/01 19:26:09 anant Exp $ +// + +require_once 'PEAR.php'; + +/** + * Provides timing and profiling information. + * + * Example 1: Automatic profiling start, stop, and output. + * + * + * enterSection('myFunction'); + * //do something + * $profiler->leaveSection('myFunction'); + * return; + * } + * + * //do something + * myFunction(); + * //do more + * ?> + * + * + * Example 2: Manual profiling start, stop, and output. + * + * + * enterSection('myFunction'); + * //do something + * $profiler->leaveSection('myFunction'); + * return; + * } + * + * $profiler->start(); + * //do something + * myFunction(); + * //do more + * $profiler->stop(); + * $profiler->display(); + * ?> + * + * + * @author Matthias Englert + * @copyright Copyright © 2002-2005 Matthias Englert + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 + * @category Benchmarking + * @package Benchmark + * @since 1.2.0 + */ +class Benchmark_Profiler extends PEAR { + /** + * Contains the total ex. time of each section + * + * @var array + * @access private + */ + var $_sections = array(); + + /** + * Calling stack + * + * @var array + * @access private + */ + var $_stack = array(); + + /** + * Notes how often a section was entered + * + * @var array + * @access private + */ + var $_numberOfCalls = array(); + + /** + * Notes for each section how much time is spend in sub-sections + * + * @var array + * @access private + */ + var $_subSectionsTime = array(); + + /** + * Notes for each section how often it calls which section + * + * @var array + * @access private + */ + var $_calls = array(); + + /** + * Notes for each section how often it was called by which section + * + * @var array + * @access private + */ + var $_callers = array(); + + /** + * Auto-starts and stops profiler + * + * @var boolean + * @access private + */ + var $_auto = FALSE; + + /** + * Max marker name length for non-html output + * + * @var integer + * @access private + */ + var $_maxStringLength = 0; + + /** + * Constructor, starts profiling recording + * + * @access public + */ + function Benchmark_Profiler($auto = FALSE) { + $this->_auto = $auto; + + if ($this->_auto) { + $this->start(); + } + + $this->PEAR(); + } + + /** + * Destructor, stops profiling recording + * + * @access private + */ + function _Benchmark_Profiler() { + if (isset($this->_auto) && $this->_auto) { + $this->stop(); + $this->display(); + } + } + + /** + * Returns profiling informations for a given section. + * + * @param string $section + * @return array + * @access public + */ + function getSectionInformations($section = 'Global') { + if (isset($this->_sections[$section])) { + $calls = array(); + + if (isset($this->_calls[$section])) { + $calls = $this->_calls[$section]; + } + + $callers = array(); + + if (isset($this->_callers[$section])) { + $callers = $this->_callers[$section]; + } + + $informations = array(); + + $informations['time'] = $this->_sections[$section]; + if (isset($this->_sections['Global'])) { + $informations['percentage'] = number_format(100 * $this->_sections[$section] / $this->_sections['Global'], 2, '.', ''); + } else { + $informations['percentage'] = 'N/A'; + } + $informations['calls'] = $calls; + $informations['num_calls'] = $this->_numberOfCalls[$section]; + $informations['callers'] = $callers; + + if (isset($this->_subSectionsTime[$section])) { + $informations['netto_time'] = $this->_sections[$section] - $this->_subSectionsTime[$section]; + } else { + $informations['netto_time'] = $this->_sections[$section]; + } + + return $informations; + } else { + $this->raiseError("The section '$section' does not exists.\n", NULL, PEAR_ERROR_TRIGGER, E_USER_WARNING); + } + } + + /** + * Returns profiling informations for all sections. + * + * @return array + * @access public + */ + function getAllSectionsInformations() { + $informations = array(); + + foreach($this->_sections as $section => $time) { + $informations[$section] = $this->getSectionInformations($section); + } + + return $informations; + } + + /** + * Returns formatted profiling information. + * + * @param string output format (auto, plain or html), default auto + * @see display() + * @access private + */ + function _getOutput($format) { + + /* Quickly find out the maximun length: Ineffecient, but will do for now! */ + $informations = $this->getAllSectionsInformations(); + $names = array_keys($informations); + + $maxLength = 0; + foreach ($names as $name) + { + if ($maxLength < strlen($name)) { + $maxLength = strlen($name); + } + } + $this->_maxStringLength = $maxLength; + + if ($format == 'auto') { + if (function_exists('version_compare') && + version_compare(phpversion(), '4.1', 'ge')) { + $format = isset($_SERVER['SERVER_PROTOCOL']) ? 'html' : 'plain'; + } else { + global $HTTP_SERVER_VARS; + $format = isset($HTTP_SERVER_VARS['SERVER_PROTOCOL']) ? 'html' : 'plain'; + } + } + + if ($format == 'html') { + $out = ''."\n"; + $out .= + ''. + ''. + ''. + ''. + "\n"; + } else { + $dashes = $out = str_pad("\n", ($this->_maxStringLength + 75), '-', STR_PAD_LEFT); + $out .= str_pad('Section', $this->_maxStringLength + 10); + $out .= str_pad("Total Ex Time", 22); + $out .= str_pad("Netto Ex Time", 22); + $out .= str_pad("#Calls", 10); + $out .= "Percentage\n"; + $out .= $dashes; + } + + foreach($informations as $name => $values) { + $percentage = $values['percentage']; + $calls_str = ""; + + foreach($values['calls'] as $key => $val) { + if ($calls_str) { + $calls_str .= ", "; + } + + $calls_str .= "$key ($val)"; + } + + $callers_str = ""; + + foreach($values['callers'] as $key => $val) { + if ($callers_str) { + $callers_str .= ", "; + } + + $callers_str .= "$key ($val)"; + } + + if ($format == 'html') { + $out .= ""; + if (is_numeric($values['percentage'])) { + $out .= "\n"; + } else { + $out .= "\n"; + } + $out .= ""; + } else { + $out .= str_pad($name, $this->_maxStringLength + 10); + $out .= str_pad($values['time'], 22); + $out .= str_pad($values['netto_time'], 22); + $out .= str_pad($values['num_calls'], 10); + if (is_numeric($values['percentage'])) { + $out .= str_pad($values['percentage']."%\n", 8, ' ', STR_PAD_LEFT); + } else { + $out .= str_pad($values['percentage']."\n", 8, ' ', STR_PAD_LEFT); + } + } + } + + if ($format == 'html') { + return $out . '
 total ex. timenetto ex. time#calls%callscallers
$name{$values['time']}{$values['netto_time']}{$values['num_calls']}{$values['percentage']}%{$values['percentage']}$calls_str$callers_str
'; + } else { + return $out; + } + } + + /** + * Returns formatted profiling information. + * + * @param string output format (auto, plain or html), default auto + * @access public + */ + function display($format = 'auto') { + echo $this->_getOutput($format); + } + + /** + * Enters "Global" section. + * + * @see enterSection(), stop() + * @access public + */ + function start() { + $this->enterSection('Global'); + } + + /** + * Leaves "Global" section. + * + * @see leaveSection(), start() + * @access public + */ + function stop() { + $this->leaveSection('Global'); + } + + /** + * Enters code section. + * + * @param string name of the code section + * @see start(), leaveSection() + * @access public + */ + function enterSection($name) { + if (count($this->_stack)) { + if (isset($this->_callers[$name][$this->_stack[count($this->_stack) - 1]["name"]])) { + $this->_callers[$name][$this->_stack[count($this->_stack) - 1]["name"]]++; + } else { + $this->_callers[$name][$this->_stack[count($this->_stack) - 1]["name"]] = 1; + } + + if (isset($this->_calls[$this->_stack[count($this->_stack) - 1]["name"]][$name])) { + $this->_calls[$this->_stack[count($this->_stack) - 1]["name"]][$name]++; + } else { + $this->_calls[$this->_stack[count($this->_stack) - 1]["name"]][$name] = 1; + } + } else { + if ($name != 'Global') { + $this->raiseError("tried to enter section ".$name." but profiling was not started\n", NULL, PEAR_ERROR_DIE); + } + } + + if (isset($this->_numberOfCalls[$name])) { + $this->_numberOfCalls[$name]++; + } else { + $this->_numberOfCalls[$name] = 1; + } + + array_push($this->_stack, array("name" => $name, "time" => $this->_getMicrotime())); + } + + /** + * Leaves code section. + * + * @param string name of the marker to be set + * @see stop(), enterSection() + * @access public + */ + function leaveSection($name) { + $microtime = $this->_getMicrotime(); + + if (!count($this->_stack)) { + $this->raiseError("tried to leave section ".$name." but profiling was not started\n", NULL, PEAR_ERROR_DIE); + } + + $x = array_pop($this->_stack); + + if ($x["name"] != $name) { + $this->raiseError("reached end of section $name but expecting end of " . $x["name"]."\n", NULL, PEAR_ERROR_DIE); + } + + if (isset($this->_sections[$name])) { + $this->_sections[$name] += $microtime - $x["time"]; + } else { + $this->_sections[$name] = $microtime - $x["time"]; + } + + $parent = array_pop($this->_stack); + + if (isset($parent)) { + if (isset($this->_subSectionsTime[$parent['name']])) { + $this->_subSectionsTime[$parent['name']] += $microtime - $x['time']; + } else { + $this->_subSectionsTime[$parent['name']] = $microtime - $x['time']; + } + + array_push($this->_stack, $parent); + } + } + + /** + * Wrapper for microtime(). + * + * @return float + * @access private + * @since 1.3.0 + */ + function _getMicrotime() { + $microtime = explode(' ', microtime()); + return $microtime[1] . substr($microtime[0], 1); + } +} diff --git a/buildscripts/Benchmark/Timer.php b/buildscripts/Benchmark/Timer.php new file mode 100644 index 00000000..d713e6b2 --- /dev/null +++ b/buildscripts/Benchmark/Timer.php @@ -0,0 +1,319 @@ +. | +// +------------------------------------------------------------------------+ +// | This source file is subject to the New BSD license, That is bundled | +// | with this package in the file LICENSE, and is available through | +// | the world-wide-web at | +// | http://www.opensource.org/licenses/bsd-license.php | +// | If you did not receive a copy of the new BSDlicense and are unable | +// | to obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +------------------------------------------------------------------------+ +// +// $Id: Timer.php,v 1.16 2006/03/01 13:41:39 matthias Exp $ +// + +require_once 'PEAR.php'; + +/** + * Provides timing and profiling information. + * + * Example 1: Automatic profiling start, stop, and output. + * + * + * setMarker('Marker 1'); + * ?> + * + * + * Example 2: Manual profiling start, stop, and output. + * + * + * start(); + * $timer->setMarker('Marker 1'); + * $timer->stop(); + * + * $timer->display(); // to output html formated + * // AND/OR : + * $profiling = $timer->getProfiling(); // get the profiler info as an associative array + * ?> + * + * + * @author Sebastian Bergmann + * @author Ludovico Magnocavallo + * @copyright Copyright © 2002-2005 Sebastian Bergmann + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 + * @category Benchmarking + * @package Benchmark + */ +class Benchmark_Timer extends PEAR { + /** + * Contains the markers. + * + * @var array + * @access private + */ + var $markers = array(); + + /** + * Auto-start and stop timer. + * + * @var boolean + * @access private + */ + var $auto = FALSE; + + /** + * Max marker name length for non-html output. + * + * @var integer + * @access private + */ + var $maxStringLength = 0; + + /** + * Constructor. + * + * @param boolean $auto + * @access public + */ + function Benchmark_Timer($auto = FALSE) { + $this->auto = $auto; + + if ($this->auto) { + $this->start(); + } + + $this->PEAR(); + } + + /** + * Destructor. + * + * @access private + */ + function _Benchmark_Timer() { + if ($this->auto) { + $this->stop(); + $this->display(); + } + } + + /** + * Set "Start" marker. + * + * @see setMarker(), stop() + * @access public + */ + function start() { + $this->setMarker('Start'); + } + + /** + * Set "Stop" marker. + * + * @see setMarker(), start() + * @access public + */ + function stop() { + $this->setMarker('Stop'); + } + + /** + * Set marker. + * + * @param string $name Name of the marker to be set. + * @see start(), stop() + * @access public + */ + function setMarker($name) { + $this->markers[$name] = $this->_getMicrotime(); + } + + /** + * Returns the time elapsed betweens two markers. + * + * @param string $start start marker, defaults to "Start" + * @param string $end end marker, defaults to "Stop" + * @return double $time_elapsed time elapsed between $start and $end + * @access public + */ + function timeElapsed($start = 'Start', $end = 'Stop') { + if ($end == 'Stop' && !isset($this->markers['Stop'])) { + $this->markers['Stop'] = $this->_getMicrotime(); + } + + if (extension_loaded('bcmath')) { + return bcsub($this->markers[$end], $this->markers[$start], 6); + } else { + return $this->markers[$end] - $this->markers[$start]; + } + } + + /** + * Returns profiling information. + * + * $profiling[x]['name'] = name of marker x + * $profiling[x]['time'] = time index of marker x + * $profiling[x]['diff'] = execution time from marker x-1 to this marker x + * $profiling[x]['total'] = total execution time up to marker x + * + * @return array + * @access public + */ + function getProfiling() { + $i = $total = 0; + $result = array(); + $temp = reset($this->markers); + $this->maxStringLength = 0; + + foreach ($this->markers as $marker => $time) { + if (extension_loaded('bcmath')) { + $diff = bcsub($time, $temp, 6); + $total = bcadd($total, $diff, 6); + } else { + $diff = $time - $temp; + $total = $total + $diff; + } + + $result[$i]['name'] = $marker; + $result[$i]['time'] = $time; + $result[$i]['diff'] = $diff; + $result[$i]['total'] = $total; + + $this->maxStringLength = (strlen($marker) > $this->maxStringLength ? strlen($marker) + 1 : $this->maxStringLength); + + $temp = $time; + $i++; + } + + $result[0]['diff'] = '-'; + $result[0]['total'] = '-'; + $this->maxStringLength = (strlen('total') > $this->maxStringLength ? strlen('total') : $this->maxStringLength); + $this->maxStringLength += 2; + + return $result; + } + + /** + * Return formatted profiling information. + * + * @param boolean $showTotal Optionnaly includes total in output, default no + * @param string $format output format (auto, plain or html), default auto + * @return string + * @see getProfiling() + * @access public + */ + function getOutput($showTotal = FALSE, $format = 'auto') { + if ($format == 'auto') { + if (function_exists('version_compare') && + version_compare(phpversion(), '4.1', 'ge')) + { + $format = isset($_SERVER['SERVER_PROTOCOL']) ? 'html' : 'plain'; + } else { + global $HTTP_SERVER_VARS; + $format = isset($HTTP_SERVER_VARS['SERVER_PROTOCOL']) ? 'html' : 'plain'; + } + } + + $total = $this->TimeElapsed(); + $result = $this->getProfiling(); + $dashes = ''; + + if ($format == 'html') { + $out = ''."\n"; + $out .= ''. + ($showTotal ? + '' + : '')."\n"; + } else { + $dashes = $out = str_pad("\n", + $this->maxStringLength + ($showTotal ? 70 : 45), '-', STR_PAD_LEFT); + $out .= str_pad('marker', $this->maxStringLength) . + str_pad("time index", 22) . + str_pad("ex time", 16) . + str_pad("perct ", 8) . + ($showTotal ? ' '.str_pad("elapsed", 16)."perct" : '')."\n" . + $dashes; + } + + foreach ($result as $k => $v) { + $perc = (($v['diff'] * 100) / $total); + $tperc = (($v['total'] * 100) / $total); + + if ($format == 'html') { + $out .= "". + ($showTotal ? + "" : ''). + "\n"; + } else { + $out .= str_pad($v['name'], $this->maxStringLength, ' ') . + str_pad($v['time'], 22) . + str_pad($v['diff'], 14) . + str_pad(number_format($perc, 2, '.', '')."%",8, ' ', STR_PAD_LEFT) . + ($showTotal ? ' '. + str_pad($v['total'], 14) . + str_pad(number_format($tperc, 2, '.', '')."%", + 8, ' ', STR_PAD_LEFT) : ''). + "\n"; + } + + $out .= $dashes; + } + + if ($format == 'html') { + $out .= "".($showTotal ? "" : "")."\n"; + $out .= "
 time indexex time%elapsed%
" . $v['name'] . + "" . $v['time'] . + "" . $v['diff'] . + "" . number_format($perc, 2, '.', '') . + "%" . $v['total'] . + "" . + number_format($tperc, 2, '.', '') . + "%
total-${total}100.00%--
\n"; + } else { + $out .= str_pad('total', $this->maxStringLength); + $out .= str_pad('-', 22); + $out .= str_pad($total, 15); + $out .= "100.00%\n"; + $out .= $dashes; + } + + return $out; + } + + /** + * Prints the information returned by getOutput(). + * + * @param boolean $showTotal Optionnaly includes total in output, default no + * @param string $format output format (auto, plain or html), default auto + * @see getOutput() + * @access public + */ + function display($showTotal = FALSE, $format = 'auto') { + print $this->getOutput($showTotal, $format); + } + + /** + * Wrapper for microtime(). + * + * @return float + * @access private + * @since 1.3.0 + */ + function _getMicrotime() { + $microtime = explode(' ', microtime()); + return $microtime[1] . substr($microtime[0], 1); + } +} diff --git a/buildscripts/Benchmark/doc/timer_example.php b/buildscripts/Benchmark/doc/timer_example.php new file mode 100644 index 00000000..93dd05c6 --- /dev/null +++ b/buildscripts/Benchmark/doc/timer_example.php @@ -0,0 +1,18 @@ +start(); +wait(10); +$timer->setMarker('Mark1'); +echo "Elapsed time between Start and Mark1: " . + $timer->timeElapsed('Start', 'Mark1') . "\n"; +wait(50); +$timer->stop(); +$timer->display(); diff --git a/buildscripts/PHPUnit2/Extensions/ExceptionTestCase.php b/buildscripts/PHPUnit2/Extensions/ExceptionTestCase.php new file mode 100644 index 00000000..80afd1b5 --- /dev/null +++ b/buildscripts/PHPUnit2/Extensions/ExceptionTestCase.php @@ -0,0 +1,122 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: ExceptionTestCase.php,v 1.15.2.6 2006/02/20 07:42:59 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +require_once 'PHPUnit2/Framework/TestCase.php'; + +/** + * A TestCase that expects a specified Exception to be thrown. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + */ +class PHPUnit2_Extensions_ExceptionTestCase extends PHPUnit2_Framework_TestCase { + /** + * The name of the expected Exception. + * + * @var mixed + * @access private + */ + private $expectedException = NULL; + + /** + * @return string + * @access public + * @since Method available since Release 2.2.0 + */ + public function getExpectedException() { + return $this->expectedException; + } + + /** + * @param mixed $exceptionName + * @access public + * @since Method available since Release 2.2.0 + */ + public function setExpectedException($exceptionName) { + if ((is_string($exceptionName) && class_exists($exceptionName)) || $exceptionName === NULL) { + $this->expectedException = $exceptionName; + } + } + + /** + * @access protected + */ + protected function runTest() { + try { + parent::runTest(); + } + + catch (Exception $e) { + if ($this->expectedException !== NULL && + $e instanceof $this->expectedException) { + return; + } else { + throw $e; + } + } + + if ($this->expectedException !== NULL) { + $this->fail('Expected exception ' . $this->expectedException); + } + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Extensions/PerformanceTestCase.php b/buildscripts/PHPUnit2/Extensions/PerformanceTestCase.php new file mode 100644 index 00000000..38b249a6 --- /dev/null +++ b/buildscripts/PHPUnit2/Extensions/PerformanceTestCase.php @@ -0,0 +1,128 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: PerformanceTestCase.php,v 1.15.2.5 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.1.0 + */ + +require_once 'PHPUnit2/Framework/TestCase.php'; + +require_once 'Benchmark/Timer.php'; + +/** + * A TestCase that expects a TestCase to be executed + * meeting a given time limit. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.1.0 + */ +class PHPUnit2_Extensions_PerformanceTestCase extends PHPUnit2_Framework_TestCase { + /** + * @var integer + * @access private + */ + private $maxRunningTime = 0; + + /** + * @access protected + */ + protected function runTest() { + $timer = new Benchmark_Timer; + + $timer->start(); + parent::runTest(); + $timer->stop(); + + if ($this->maxRunningTime != 0 && + $timer->timeElapsed() > $this->maxRunningTime) { + $this->fail( + sprintf( + 'expected running time: <= %s but was: %s', + + $this->maxRunningTime, + $timer->timeElapsed() + ) + ); + } + } + + /** + * @param integer $maxRunningTime + * @throws Exception + * @access public + * @since Method available since Release 2.3.0 + */ + public function setMaxRunningTime($maxRunningTime) { + if (is_integer($maxRunningTime) && + $maxRunningTime >= 0) { + $this->maxRunningTime = $maxRunningTime; + } else { + throw new Exception; + } + } + + /** + * @return integer + * @access public + * @since Method available since Release 2.3.0 + */ + public function getMaxRunningTime() { + return $this->maxRunningTime; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Extensions/RepeatedTest.php b/buildscripts/PHPUnit2/Extensions/RepeatedTest.php new file mode 100644 index 00000000..c23b0915 --- /dev/null +++ b/buildscripts/PHPUnit2/Extensions/RepeatedTest.php @@ -0,0 +1,138 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: RepeatedTest.php,v 1.15.2.4 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +require_once 'PHPUnit2/Extensions/TestDecorator.php'; + +/** + * A Decorator that runs a test repeatedly. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + */ +class PHPUnit2_Extensions_RepeatedTest extends PHPUnit2_Extensions_TestDecorator { + /** + * @var integer + * @access private + */ + private $timesRepeat = 1; + + /** + * Constructor. + * + * @param PHPUnit2_Framework_Test $test + * @param integer $timesRepeat + * @throws Exception + * @access public + */ + public function __construct(PHPUnit2_Framework_Test $test, $timesRepeat = 1) { + parent::__construct($test); + + if (is_integer($timesRepeat) && + $timesRepeat >= 0) { + $this->timesRepeat = $timesRepeat; + } else { + throw new Exception( + 'Argument 2 must be a positive integer.' + ); + } + } + + /** + * Counts the number of test cases that + * will be run by this test. + * + * @return integer + * @access public + */ + public function countTestCases() { + return $this->timesRepeat * $this->test->countTestCases(); + } + + /** + * Runs the decorated test and collects the + * result in a TestResult. + * + * @param PHPUnit2_Framework_TestResult $result + * @return PHPUnit2_Framework_TestResult + * @throws Exception + * @access public + */ + public function run($result = NULL) { + if ($result === NULL) { + $result = $this->createResult(); + } + + // XXX: Workaround for missing ability to declare type-hinted parameters as optional. + else if (!($result instanceof PHPUnit2_Framework_TestResult)) { + throw new Exception( + 'Argument 1 must be an instance of PHPUnit2_Framework_TestResult.' + ); + } + + for ($i = 0; $i < $this->timesRepeat && !$result->shouldStop(); $i++) { + $this->test->run($result); + } + + return $result; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Extensions/TestDecorator.php b/buildscripts/PHPUnit2/Extensions/TestDecorator.php new file mode 100644 index 00000000..3557eeca --- /dev/null +++ b/buildscripts/PHPUnit2/Extensions/TestDecorator.php @@ -0,0 +1,174 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: TestDecorator.php,v 1.14.2.4 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +require_once 'PHPUnit2/Framework/Assert.php'; +require_once 'PHPUnit2/Framework/Test.php'; +require_once 'PHPUnit2/Framework/TestResult.php'; + +/** + * A Decorator for Tests. + * + * Use TestDecorator as the base class for defining new + * test decorators. Test decorator subclasses can be introduced + * to add behaviour before or after a test is run. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + */ +class PHPUnit2_Extensions_TestDecorator extends PHPUnit2_Framework_Assert implements PHPUnit2_Framework_Test { + /** + * The Test to be decorated. + * + * @var object + * @access protected + */ + protected $test = NULL; + + /** + * Constructor. + * + * @param PHPUnit2_Framework_Test $test + * @access public + */ + public function __construct(PHPUnit2_Framework_Test $test) { + $this->test = $test; + } + + /** + * Returns a string representation of the test. + * + * @return string + * @access public + */ + public function toString() { + return $this->test->toString(); + } + + /** + * Runs the test and collects the + * result in a TestResult. + * + * @param PHPUnit2_Framework_TestResult $result + * @access public + */ + public function basicRun(PHPUnit2_Framework_TestResult $result) { + $this->test->run($result); + } + + /** + * Counts the number of test cases that + * will be run by this test. + * + * @return integer + * @access public + */ + public function countTestCases() { + return $this->test->countTestCases(); + } + + /** + * Creates a default TestResult object. + * + * @return PHPUnit2_Framework_TestResult + * @access protected + */ + protected function createResult() { + return new PHPUnit2_Framework_TestResult; + } + + /** + * Returns the test to be run. + * + * @return PHPUnit2_Framework_Test + * @access public + */ + public function getTest() { + return $this->test; + } + + /** + * Runs the decorated test and collects the + * result in a TestResult. + * + * @param PHPUnit2_Framework_TestResult $result + * @return PHPUnit2_Framework_TestResult + * @throws Exception + * @access public + */ + public function run($result = NULL) { + if ($result === NULL) { + $result = $this->createResult(); + } + + // XXX: Workaround for missing ability to declare type-hinted parameters as optional. + else if (!($result instanceof PHPUnit2_Framework_TestResult)) { + throw new Exception( + 'Argument 1 must be an instance of PHPUnit2_Framework_TestResult.' + ); + } + + $this->basicRun($result); + + return $result; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Extensions/TestSetup.php b/buildscripts/PHPUnit2/Extensions/TestSetup.php new file mode 100644 index 00000000..4d28f931 --- /dev/null +++ b/buildscripts/PHPUnit2/Extensions/TestSetup.php @@ -0,0 +1,154 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: TestSetup.php,v 1.13.2.6 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +require_once 'PHPUnit2/Framework/TestSuite.php'; +require_once 'PHPUnit2/Extensions/TestDecorator.php'; + +/** + * A Decorator to set up and tear down additional fixture state. + * Subclass TestSetup and insert it into your tests when you want + * to set up additional state once before the tests are run. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + */ +class PHPUnit2_Extensions_TestSetup extends PHPUnit2_Extensions_TestDecorator { + /** + * Runs the decorated test and collects the + * result in a TestResult. + * + * @param PHPUnit2_Framework_TestResult $result + * @return PHPUnit2_Framework_TestResult + * @throws Exception + * @access public + */ + public function run($result = NULL) { + if ($result === NULL) { + $result = $this->createResult(); + } + + // XXX: Workaround for missing ability to declare type-hinted parameters as optional. + else if (!($result instanceof PHPUnit2_Framework_TestResult)) { + throw new Exception( + 'Argument 1 must be an instance of PHPUnit2_Framework_TestResult.' + ); + } + + $this->setUp(); + $this->copyFixtureToTest(); + $this->basicRun($result); + $this->tearDown(); + + return $result; + } + + /** + * Copies the fixture set up by setUp() to the test. + * + * @access private + * @since Method available since Release 2.3.0 + */ + private function copyFixtureToTest() { + $object = new ReflectionClass($this); + + foreach ($object->getProperties() as $property) { + $name = $property->getName(); + + if ($name != 'test') { + $this->doCopyFixtureToTest($this->test, $name, $this->$name); + } + } + } + + /** + * @access private + * @since Method available since Release 2.3.0 + */ + private function doCopyFixtureToTest($object, $name, &$value) { + if ($object instanceof PHPUnit2_Framework_TestSuite) { + foreach ($object->tests() as $test) { + $this->doCopyFixtureToTest($test, $name, $value); + } + } else { + $object->$name =& $value; + } + } + + /** + * Sets up the fixture. Override to set up additional fixture + * state. + * + * @access protected + */ + protected function setUp() { + } + + /** + * Tears down the fixture. Override to tear down the additional + * fixture state. + * + * @access protected + */ + protected function tearDown() { + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Framework/Assert.php b/buildscripts/PHPUnit2/Framework/Assert.php new file mode 100644 index 00000000..3465afea --- /dev/null +++ b/buildscripts/PHPUnit2/Framework/Assert.php @@ -0,0 +1,626 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: Assert.php,v 1.45.2.4 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +require_once 'PHPUnit2/Framework/AssertionFailedError.php'; +require_once 'PHPUnit2/Framework/ComparisonFailure.php'; + +/** + * A set of assert methods. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + * @static + */ +class PHPUnit2_Framework_Assert { + /** + * @var boolean + * @access private + * @static + */ + private static $looselyTyped = FALSE; + + /** + * Protect constructor since it is a static only class. + * + * @access protected + */ + protected function __construct() { + } + + /** + * Asserts that a haystack contains a needle. + * + * @param mixed $needle + * @param mixed $haystack + * @param string $message + * @access public + * @static + * @since Method available since Release 2.1.0 + */ + public static function assertContains($needle, $haystack, $message = '') { + self::doAssertContains($needle, $haystack, TRUE, $message); + } + + /** + * Asserts that a haystack does not contain a needle. + * + * @param mixed $needle + * @param mixed $haystack + * @param string $message + * @access public + * @static + * @since Method available since Release 2.1.0 + */ + public static function assertNotContains($needle, $haystack, $message = '') { + self::doAssertContains($needle, $haystack, FALSE, $message); + } + + /** + * @param mixed $needle + * @param mixed $haystack + * @param boolean $condition + * @param string $message + * @throws Exception + * @access private + * @static + * @since Method available since Release 2.2.0 + */ + private static function doAssertContains($needle, $haystack, $condition, $message) { + $found = FALSE; + + if (is_array($haystack) || + (is_object($haystack) && $haystack instanceof Iterator)) { + foreach ($haystack as $straw) { + if ($straw === $needle) { + $found = TRUE; + break; + } + } + } + + else if (is_string($needle) && is_string($haystack)) { + if (strpos($haystack, $needle) !== FALSE) { + $found = TRUE; + } + } + + else { + throw new Exception; + } + + if ($condition && !$found) { + self::fail( + sprintf( + '%s%s"%s" does not contain "%s"', + + $message, + ($message != '') ? ' ' : '', + self::objectToString($haystack), + self::objectToString($needle) + ) + ); + } + + else if (!$condition && $found) { + self::fail( + sprintf( + '%s%s"%s" contains "%s"', + + $message, + ($message != '') ? ' ' : '', + self::objectToString($haystack), + self::objectToString($needle) + ) + ); + } + } + + /** + * Asserts that two variables are equal. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @param mixed $delta + * @access public + * @static + */ + public static function assertEquals($expected, $actual, $message = '', $delta = 0) { + self::doAssertEquals($expected, $actual, $delta, TRUE, $message); + } + + /** + * Asserts that two variables are not equal. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @param mixed $delta + * @access public + * @static + * @since Method available since Release 2.3.0 + */ + public static function assertNotEquals($expected, $actual, $message = '', $delta = 0) { + self::doAssertEquals($expected, $actual, $delta, FALSE, $message); + } + + /** + * @param mixed $expected + * @param mixed $actual + * @param mixed $delta + * @param boolean $condition + * @param string $message + * @access private + * @static + * @since Method available since Release 2.3.0 + */ + private static function doAssertEquals($expected, $actual, $delta, $condition, $message) { + $equal = FALSE; + + if (is_array($expected)) { + if (is_array($actual)) { + self::sortArrayRecursively($actual); + self::sortArrayRecursively($expected); + + if (self::$looselyTyped) { + $actual = self::convertToString($actual); + $expected = self::convertToString($expected); + } + + $equal = (serialize($expected) == serialize($actual)); + } + } + + else if (is_float($expected) && is_float($actual) && is_float($delta)) { + $equal = (abs($expected - $actual) <= $delta); + } + + else { + $equal = (serialize($expected) == serialize($actual)); + } + + if ($condition && !$equal) { + self::failNotSame( + $expected, + $actual, + $message + ); + } + + else if (!$condition && $equal) { + self::failSame( + $expected, + $actual, + $message + ); + } + } + + /** + * Asserts that a condition is true. + * + * @param boolean $condition + * @param string $message + * @throws Exception + * @access public + * @static + */ + public static function assertTrue($condition, $message = '') { + if (is_bool($condition)) { + if (!$condition) { + self::fail($message); + } + } else { + throw new Exception; + } + } + + /** + * Asserts that a condition is false. + * + * @param boolean $condition + * @param string $message + * @throws Exception + * @access public + * @static + */ + public static function assertFalse($condition, $message = '') { + if (is_bool($condition)) { + self::assertTrue(!$condition, $message); + } else { + throw new Exception; + } + } + + /** + * Asserts that a variable is not NULL. + * + * @param mixed $actual + * @param string $message + * @access public + * @static + */ + public static function assertNotNull($actual, $message = '') { + if (is_null($actual)) { + self::fail(self::format('NOT NULL', 'NULL', $message)); + } + } + + /** + * Asserts that a variable is NULL. + * + * @param mixed $actual + * @param string $message + * @access public + * @static + */ + public static function assertNull($actual, $message = '') { + if (!is_null($actual)) { + self::fail(self::format('NULL', 'NOT NULL', $message)); + } + } + + /** + * Asserts that two variables have the same type and value. + * Used on objects, it asserts that two variables reference + * the same object. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @access public + * @static + */ + public static function assertSame($expected, $actual, $message = '') { + if ($expected !== $actual) { + self::failNotSame($expected, $actual, $message); + } + } + + /** + * Asserts that two variables do not have the same type and value. + * Used on objects, it asserts that two variables do not reference + * the same object. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @access public + * @static + */ + public static function assertNotSame($expected, $actual, $message = '') { + if ($expected === $actual) { + self::failSame($expected, $actual, $message); + } + } + + /** + * Asserts that a variable is of a given type. + * + * @param string $expected + * @param mixed $actual + * @param string $message + * @access public + * @static + */ + public static function assertType($expected, $actual, $message = '') { + self::doAssertType($expected, $actual, TRUE, $message); + } + + /** + * Asserts that a variable is not of a given type. + * + * @param string $expected + * @param mixed $actual + * @param string $message + * @access public + * @static + * @since Method available since Release 2.2.0 + */ + public static function assertNotType($expected, $actual, $message = '') { + self::doAssertType($expected, $actual, FALSE, $message); + } + + /** + * @param string $expected + * @param mixed $actual + * @param boolean $condition + * @param string $message + * @access private + * @static + * @since Method available since Release 2.2.0 + */ + private static function doAssertType($expected, $actual, $condition, $message) { + if (!is_string($expected)) { + throw new Exception; + } + + if (is_object($actual)) { + $result = $actual instanceof $expected; + } else { + $result = (gettype($actual) == $expected); + } + + if ($condition && !$result) { + self::failNotSame( + $expected, + $actual, + $message + ); + } + + else if (!$condition && $result) { + self::failSame( + $expected, + $actual, + $message + ); + } + } + + /** + * Asserts that a string matches a given regular expression. + * + * @param string $pattern + * @param string $string + * @param string $message + * @access public + * @static + */ + public static function assertRegExp($pattern, $string, $message = '') { + self::doAssertRegExp($pattern, $string, TRUE, $message); + } + + /** + * Asserts that a string does not match a given regular expression. + * + * @param string $pattern + * @param string $string + * @param string $message + * @access public + * @static + * @since Method available since Release 2.1.0 + */ + public static function assertNotRegExp($pattern, $string, $message = '') { + self::doAssertRegExp($pattern, $string, FALSE, $message); + } + + /** + * @param mixed $pattern + * @param mixed $string + * @param boolean $condition + * @param string $message + * @access private + * @static + * @since Method available since Release 2.2.0 + */ + private static function doAssertRegExp($pattern, $string, $condition, $message) { + if (!is_string($pattern) || !is_string($string)) { + throw new Exception; + } + + $result = preg_match($pattern, $string); + + if ($condition && !$result) { + self::fail( + sprintf( + '%s%s"%s" does not match pattern "%s"', + + $message, + ($message != '') ? ' ' : '', + $string, + $pattern + ) + ); + } + + else if (!$condition && $result) { + self::fail( + sprintf( + '%s%s"%s" matches pattern "%s"', + + $message, + ($message != '') ? ' ' : '', + $string, + $pattern + ) + ); + } + } + + /** + * Fails a test with the given message. + * + * @param string $message + * @throws PHPUnit2_Framework_AssertionFailedError + * @access public + * @static + */ + public static function fail($message = '') { + throw new PHPUnit2_Framework_AssertionFailedError($message); + } + + /** + * @param string $message + * @throws PHPUnit2_Framework_AssertionFailedError + * @access private + * @static + */ + private static function failSame($message) { + self::fail( + sprintf( + '%s%sexpected not same', + + $message, + ($message != '') ? ' ' : '' + ) + ); + } + + /** + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @throws PHPUnit2_Framework_AssertionFailedError + * @access private + * @static + */ + private static function failNotSame($expected, $actual, $message) { + if (is_string($expected) && is_string($actual)) { + throw new PHPUnit2_Framework_ComparisonFailure($expected, $actual, $message); + } + + self::fail( + sprintf( + '%s%sexpected same: <%s> was not: <%s>', + + $message, + ($message != '') ? ' ' : '', + self::objectToString($expected), + self::objectToString($actual) + ) + ); + } + + /** + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @access public + * @static + */ + public static function format($expected, $actual, $message) { + return sprintf( + '%s%sexpected: <%s> but was: <%s>', + + $message, + ($message != '') ? ' ' : '', + self::objectToString($expected), + self::objectToString($actual) + ); + } + + /** + * @param boolean $looselyTyped + * @access public + * @static + */ + public static function setLooselyTyped($looselyTyped) { + if (is_bool($looselyTyped)) { + self::$looselyTyped = $looselyTyped; + } + } + + /** + * Converts a value to a string. + * + * @param mixed $value + * @access private + * @static + */ + private static function convertToString($value) { + foreach ($value as $k => $v) { + if (is_array($v)) { + $value[$k] = self::convertToString($value[$k]); + } else if (is_object($v)) { + $value[$k] = self::objectToString($value[$k]); + } else { + settype($value[$k], 'string'); + } + } + + return $value; + } + + /** + * @param mixed $object + * @return string + * @access private + * @static + */ + private static function objectToString($object) { + if (is_array($object) || is_object($object)) { + $object = serialize($object); + } + + return $object; + } + + /** + * Sorts an array recursively by its keys. + * + * @param array $array + * @access private + * @static + * @author Adam Maccabee Trachtenberg + */ + private static function sortArrayRecursively(&$array) { + ksort($array); + + foreach($array as $k => $v) { + if (is_array($v)) { + self::sortArrayRecursively($array[$k]); + } + } + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Framework/AssertionFailedError.php b/buildscripts/PHPUnit2/Framework/AssertionFailedError.php new file mode 100644 index 00000000..d3db50ed --- /dev/null +++ b/buildscripts/PHPUnit2/Framework/AssertionFailedError.php @@ -0,0 +1,80 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: AssertionFailedError.php,v 1.9.2.2 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +/** + * Thrown when an assertion failed. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + */ +class PHPUnit2_Framework_AssertionFailedError extends Exception { + /** + * Wrapper for getMessage() which is declared as final. + * + * @return string + * @access public + */ + public function toString() { + return $this->getMessage(); + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Framework/ComparisonFailure.php b/buildscripts/PHPUnit2/Framework/ComparisonFailure.php new file mode 100644 index 00000000..cc8e26e6 --- /dev/null +++ b/buildscripts/PHPUnit2/Framework/ComparisonFailure.php @@ -0,0 +1,153 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: ComparisonFailure.php,v 1.13.2.3 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +require_once 'PHPUnit2/Framework/Assert.php'; +require_once 'PHPUnit2/Framework/AssertionFailedError.php'; + +/** + * Thrown when an assertion for string equality failed. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + */ +class PHPUnit2_Framework_ComparisonFailure extends PHPUnit2_Framework_AssertionFailedError { + /** + * @var string + * @access private + */ + private $expected = ''; + + /** + * @var string + * @access private + */ + private $actual = ''; + + /** + * Constructs a comparison failure. + * + * @param string $expected + * @param string $actual + * @param string $message + * @access public + */ + public function __construct($expected, $actual, $message = '') { + parent::__construct($message); + + $this->expected = ($expected === NULL) ? 'NULL' : $expected; + $this->actual = ($actual === NULL) ? 'NULL' : $actual; + } + + /** + * Returns "..." in place of common prefix and "..." in + * place of common suffix between expected and actual. + * + * @return string + * @access public + */ + public function toString() { + $end = min(strlen($this->expected), strlen($this->actual)); + $i = 0; + $j = strlen($this->expected) - 1; + $k = strlen($this->actual) - 1; + + for (; $i < $end; $i++) { + if ($this->expected[$i] != $this->actual[$i]) { + break; + } + } + + for (; $k >= $i && $j >= $i; $k--,$j--) { + if ($this->expected[$j] != $this->actual[$k]) { + break; + } + } + + if ($j < $i && $k < $i) { + $expected = $this->expected; + $actual = $this->actual; + } else { + $expected = substr($this->expected, $i, ($j + 1 - $i)); + $actual = substr($this->actual, $i, ($k + 1 - $i));; + + if ($i <= $end && $i > 0) { + $expected = '...' . $expected; + $actual = '...' . $actual; + } + + if ($j < strlen($this->expected) - 1) { + $expected .= '...'; + } + + if ($k < strlen($this->actual) - 1) { + $actual .= '...'; + } + } + + return PHPUnit2_Framework_Assert::format( + $expected, + $actual, + parent::getMessage() + ); + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Framework/Error.php b/buildscripts/PHPUnit2/Framework/Error.php new file mode 100644 index 00000000..a4bd4fd2 --- /dev/null +++ b/buildscripts/PHPUnit2/Framework/Error.php @@ -0,0 +1,88 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: Error.php,v 1.4.2.2 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.2.0 + */ + +/** + * Wrapper for PHP errors. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.2.0 + */ +class PHPUnit2_Framework_Error extends Exception { + /** + * Constructor. + * + * @param string $message + * @param integer $code + * @param string $file + * @param integer $line + * @param array $trace + * @access public + */ + public function __construct($message, $code, $file, $line, $trace) { + parent::__construct($message, $code); + + $this->file = $file; + $this->line = $line; + $this->trace = $trace; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Framework/IncompleteTest.php b/buildscripts/PHPUnit2/Framework/IncompleteTest.php new file mode 100644 index 00000000..325e6411 --- /dev/null +++ b/buildscripts/PHPUnit2/Framework/IncompleteTest.php @@ -0,0 +1,72 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: IncompleteTest.php,v 1.6.2.2 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +/** + * A marker interface for marking any exception/error as result of an unit + * test as incomplete implementation or currently not implemented. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Interface available since Release 2.0.0 + */ +interface PHPUnit2_Framework_IncompleteTest { +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Framework/IncompleteTestError.php b/buildscripts/PHPUnit2/Framework/IncompleteTestError.php new file mode 100644 index 00000000..6c2a0660 --- /dev/null +++ b/buildscripts/PHPUnit2/Framework/IncompleteTestError.php @@ -0,0 +1,75 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: IncompleteTestError.php,v 1.5.2.3 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +require_once 'PHPUnit2/Framework/AssertionFailedError.php'; +require_once 'PHPUnit2/Framework/IncompleteTest.php'; + +/** + * Extension to PHPUnit2_Framework_AssertionFailedError to mark the special + * case of an incomplete test. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + */ +class PHPUnit2_Framework_IncompleteTestError extends PHPUnit2_Framework_AssertionFailedError implements PHPUnit2_Framework_IncompleteTest { +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Framework/Test.php b/buildscripts/PHPUnit2/Framework/Test.php new file mode 100644 index 00000000..1d198f1a --- /dev/null +++ b/buildscripts/PHPUnit2/Framework/Test.php @@ -0,0 +1,87 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: Test.php,v 1.12.2.3 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +/** + * A Test can be run and collect its results. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Interface available since Release 2.0.0 + */ +interface PHPUnit2_Framework_Test { + /** + * Counts the number of test cases that will be run by this test. + * + * @return integer + * @access public + */ + public function countTestCases(); + + /** + * Runs a test and collects its result in a TestResult instance. + * + * @param PHPUnit2_Framework_TestResult $result + * @return PHPUnit2_Framework_TestResult + * @access public + */ + public function run($result = NULL); +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Framework/TestCase.php b/buildscripts/PHPUnit2/Framework/TestCase.php new file mode 100644 index 00000000..80f56932 --- /dev/null +++ b/buildscripts/PHPUnit2/Framework/TestCase.php @@ -0,0 +1,292 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: TestCase.php,v 1.32.2.5 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +require_once 'PHPUnit2/Framework/Assert.php'; +require_once 'PHPUnit2/Framework/Error.php'; +require_once 'PHPUnit2/Framework/Test.php'; +require_once 'PHPUnit2/Framework/TestResult.php'; + +/** + * A TestCase defines the fixture to run multiple tests. + * + * To define a TestCase + * + * 1) Implement a subclass of PHPUnit2_Framework_TestCase. + * 2) Define instance variables that store the state of the fixture. + * 3) Initialize the fixture state by overriding setUp(). + * 4) Clean-up after a test by overriding tearDown(). + * + * Each test runs in its own fixture so there can be no side effects + * among test runs. + * + * Here is an example: + * + * + * value1 = 2; + * $this->value2 = 3; + * } + * } + * ?> + * + * + * For each test implement a method which interacts with the fixture. + * Verify the expected results with assertions specified by calling + * assert with a boolean. + * + * + * assertTrue($this->value1 + $this->value2 == 5); + * } + * ?> + * + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + * @abstract + */ +abstract class PHPUnit2_Framework_TestCase extends PHPUnit2_Framework_Assert implements PHPUnit2_Framework_Test { + /** + * The name of the test case. + * + * @var string + * @access private + */ + private $name = NULL; + + /** + * Constructs a test case with the given name. + * + * @param string + * @access public + */ + public function __construct($name = NULL) { + if ($name !== NULL) { + $this->setName($name); + } + } + + /** + * Returns a string representation of the test case. + * + * @return string + * @access public + */ + public function toString() { + $class = new ReflectionClass($this); + + return sprintf( + '%s(%s)', + + $this->getName(), + $class->name + ); + } + + /** + * Counts the number of test cases executed by run(TestResult result). + * + * @return integer + * @access public + */ + public function countTestCases() { + return 1; + } + + /** + * Gets the name of a TestCase. + * + * @return string + * @access public + */ + public function getName() { + return $this->name; + } + + /** + * Runs the test case and collects the results in a TestResult object. + * If no TestResult object is passed a new one will be created. + * + * @param PHPUnit2_Framework_TestResult $result + * @return PHPUnit2_Framework_TestResult + * @throws Exception + * @access public + */ + public function run($result = NULL) { + if ($result === NULL) { + $result = $this->createResult(); + } + + // XXX: Workaround for missing ability to declare type-hinted parameters as optional. + else if (!($result instanceof PHPUnit2_Framework_TestResult)) { + throw new Exception( + 'Argument 1 must be an instance of PHPUnit2_Framework_TestResult.' + ); + } + + $result->run($this); + + return $result; + } + + /** + * Runs the bare test sequence. + * + * @access public + */ + public function runBare() { + $catchedException = NULL; + + $this->setUp(); + + try { + $this->runTest(); + } + + catch (Exception $e) { + $catchedException = $e; + } + + $this->tearDown(); + + // Workaround for missing "finally". + if ($catchedException !== NULL) { + throw $catchedException; + } + } + + /** + * Override to run the test and assert its state. + * + * @throws PHPUnit2_Framework_Error + * @access protected + */ + protected function runTest() { + if ($this->name === NULL) { + throw new PHPUnit2_Framework_Error( + 'PHPUnit2_Framework_TestCase::$name must not be NULL.' + ); + } + + try { + $class = new ReflectionClass($this); + $method = $class->getMethod($this->name); + } + + catch (ReflectionException $e) { + $this->fail($e->getMessage()); + } + + $method->invoke($this); + } + + /** + * Sets the name of a TestCase. + * + * @param string + * @access public + */ + public function setName($name) { + $this->name = $name; + } + + /** + * Creates a default TestResult object. + * + * @return PHPUnit2_Framework_TestResult + * @access protected + */ + protected function createResult() { + return new PHPUnit2_Framework_TestResult; + } + + /** + * Sets up the fixture, for example, open a network connection. + * This method is called before a test is executed. + * + * @access protected + */ + protected function setUp() { + } + + /** + * Tears down the fixture, for example, close a network connection. + * This method is called after a test is executed. + * + * @access protected + */ + protected function tearDown() { + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Framework/TestFailure.php b/buildscripts/PHPUnit2/Framework/TestFailure.php new file mode 100644 index 00000000..4957e4e6 --- /dev/null +++ b/buildscripts/PHPUnit2/Framework/TestFailure.php @@ -0,0 +1,154 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: TestFailure.php,v 1.10.2.3 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +require_once 'PHPUnit2/Framework/AssertionFailedError.php'; +require_once 'PHPUnit2/Framework/Test.php'; + +/** + * A TestFailure collects a failed test together with the caught exception. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + */ +class PHPUnit2_Framework_TestFailure { + /** + * @var PHPUnit2_Framework_Test + * @access protected + */ + protected $failedTest; + + /** + * @var Exception + * @access protected + */ + protected $thrownException; + + /** + * Constructs a TestFailure with the given test and exception. + * + * @param PHPUnit2_Framework_Test $failedTest + * @param Exception $thrownException + * @access public + */ + public function __construct(PHPUnit2_Framework_Test $failedTest, Exception $thrownException) { + $this->failedTest = $failedTest; + $this->thrownException = $thrownException; + } + + /** + * Returns a short description of the failure. + * + * @return string + * @access public + */ + public function toString() { + return sprintf( + '%s: %s', + + $this->failedTest, + $this->thrownException->getMessage() + ); + } + + /** + * Gets the failed test. + * + * @return Test + * @access public + */ + public function failedTest() { + return $this->failedTest; + } + + /** + * Gets the thrown exception. + * + * @return Exception + * @access public + */ + public function thrownException() { + return $this->thrownException; + } + + /** + * Returns the exception's message. + * + * @return string + * @access public + */ + public function exceptionMessage() { + return $this->thrownException()->getMessage(); + } + + /** + * Returns TRUE if the thrown exception + * is of type AssertionFailedError. + * + * @return boolean + * @access public + */ + public function isFailure() { + return ($this->thrownException() instanceof PHPUnit2_Framework_AssertionFailedError); + } +} + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Framework/TestListener.php b/buildscripts/PHPUnit2/Framework/TestListener.php new file mode 100644 index 00000000..79f11ffb --- /dev/null +++ b/buildscripts/PHPUnit2/Framework/TestListener.php @@ -0,0 +1,135 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: TestListener.php,v 1.11.2.3 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +require_once 'PHPUnit2/Framework/AssertionFailedError.php'; +require_once 'PHPUnit2/Framework/TestSuite.php'; + +/** + * A Listener for test progress. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Interface available since Release 2.0.0 + */ +interface PHPUnit2_Framework_TestListener { + /** + * An error occurred. + * + * @param PHPUnit2_Framework_Test $test + * @param Exception $e + * @access public + */ + public function addError(PHPUnit2_Framework_Test $test, Exception $e); + + /** + * A failure occurred. + * + * @param PHPUnit2_Framework_Test $test + * @param PHPUnit2_Framework_AssertionFailedError $e + * @access public + */ + public function addFailure(PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $e); + + /** + * Incomplete test. + * + * @param PHPUnit2_Framework_Test $test + * @param Exception $e + * @access public + */ + public function addIncompleteTest(PHPUnit2_Framework_Test $test, Exception $e); + + /** + * A test suite started. + * + * @param PHPUnit2_Framework_TestSuite $suite + * @access public + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit2_Framework_TestSuite $suite); + + /** + * A test suite ended. + * + * @param PHPUnit2_Framework_TestSuite $suite + * @access public + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit2_Framework_TestSuite $suite); + + /** + * A test started. + * + * @param PHPUnit2_Framework_Test $test + * @access public + */ + public function startTest(PHPUnit2_Framework_Test $test); + + /** + * A test ended. + * + * @param PHPUnit2_Framework_Test $test + * @access public + */ + public function endTest(PHPUnit2_Framework_Test $test); +} + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Framework/TestResult.php b/buildscripts/PHPUnit2/Framework/TestResult.php new file mode 100644 index 00000000..17adb529 --- /dev/null +++ b/buildscripts/PHPUnit2/Framework/TestResult.php @@ -0,0 +1,447 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: TestResult.php,v 1.32.2.7 2006/02/25 09:44:23 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +require_once 'PHPUnit2/Framework/AssertionFailedError.php'; +require_once 'PHPUnit2/Framework/IncompleteTest.php'; +require_once 'PHPUnit2/Framework/TestFailure.php'; +require_once 'PHPUnit2/Framework/TestListener.php'; +require_once 'PHPUnit2/Util/ErrorHandler.php'; +require_once 'PHPUnit2/Util/Filter.php'; + +/** + * A TestResult collects the results of executing a test case. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + */ +class PHPUnit2_Framework_TestResult { + /** + * @var array + * @access protected + */ + protected $errors = array(); + + /** + * @var array + * @access protected + */ + protected $failures = array(); + + /** + * @var array + * @access protected + */ + protected $notImplemented = array(); + + /** + * @var array + * @access protected + */ + protected $listeners = array(); + + /** + * @var integer + * @access protected + */ + protected $runTests = 0; + + /** + * Code Coverage information provided by Xdebug. + * + * @var array + * @access protected + */ + protected $codeCoverageInformation = array(); + + /** + * @var boolean + * @access protected + */ + protected $collectCodeCoverageInformation = FALSE; + + /** + * @var boolean + * @access private + */ + private $stop = FALSE; + + /** + * Registers a TestListener. + * + * @param PHPUnit2_Framework_TestListener + * @access public + */ + public function addListener(PHPUnit2_Framework_TestListener $listener) { + $this->listeners[] = $listener; + } + + /** + * Unregisters a TestListener. + * + * @param PHPUnit2_Framework_TestListener $listener + * @access public + */ + public function removeListener(PHPUnit2_Framework_TestListener $listener) { + for ($i = 0; $i < sizeof($this->listeners); $i++) { + if ($this->listeners[$i] === $listener) { + unset($this->listeners[$i]); + } + } + } + + /** + * Adds an error to the list of errors. + * The passed in exception caused the error. + * + * @param PHPUnit2_Framework_Test $test + * @param Exception $e + * @access public + */ + public function addError(PHPUnit2_Framework_Test $test, Exception $e) { + if ($e instanceof PHPUnit2_Framework_IncompleteTest) { + $this->notImplemented[] = new PHPUnit2_Framework_TestFailure($test, $e); + + foreach ($this->listeners as $listener) { + $listener->addIncompleteTest($test, $e); + } + } else { + $this->errors[] = new PHPUnit2_Framework_TestFailure($test, $e); + + foreach ($this->listeners as $listener) { + $listener->addError($test, $e); + } + } + } + + /** + * Adds a failure to the list of failures. + * The passed in exception caused the failure. + * + * @param PHPUnit2_Framework_Test $test + * @param PHPUnit2_Framework_AssertionFailedError $e + * @access public + */ + public function addFailure(PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $e) { + if ($e instanceof PHPUnit2_Framework_IncompleteTest) { + $this->notImplemented[] = new PHPUnit2_Framework_TestFailure($test, $e); + + foreach ($this->listeners as $listener) { + $listener->addIncompleteTest($test, $e); + } + } else { + $this->failures[] = new PHPUnit2_Framework_TestFailure($test, $e); + + foreach ($this->listeners as $listener) { + $listener->addFailure($test, $e); + } + } + } + + /** + * Informs the result that a testsuite will be started. + * + * @param PHPUnit2_Framework_TestSuite $suite + * @access public + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit2_Framework_TestSuite $suite) { + foreach ($this->listeners as $listener) { + $listener->startTestSuite($suite); + } + } + + /** + * Informs the result that a testsuite was completed. + * + * @param PHPUnit2_Framework_TestSuite $suite + * @access public + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit2_Framework_TestSuite $suite) { + foreach ($this->listeners as $listener) { + $listener->endTestSuite($suite); + } + } + + /** + * Informs the result that a test will be started. + * + * @param PHPUnit2_Framework_Test $test + * @access public + */ + public function startTest(PHPUnit2_Framework_Test $test) { + $this->runTests += $test->countTestCases(); + + foreach ($this->listeners as $listener) { + $listener->startTest($test); + } + } + + /** + * Informs the result that a test was completed. + * + * @param PHPUnit2_Framework_Test + * @access public + */ + public function endTest(PHPUnit2_Framework_Test $test) { + foreach ($this->listeners as $listener) { + $listener->endTest($test); + } + } + + /** + * Returns TRUE if no incomplete test occured. + * + * @return boolean + * @access public + */ + public function allCompletlyImplemented() { + return $this->notImplementedCount() == 0; + } + + /** + * Gets the number of incomplete tests. + * + * @return integer + * @access public + */ + public function notImplementedCount() { + return sizeof($this->notImplemented); + } + + /** + * Returns an Enumeration for the incomplete tests. + * + * @return array + * @access public + */ + public function notImplemented() { + return $this->notImplemented; + } + + /** + * Gets the number of detected errors. + * + * @return integer + * @access public + */ + public function errorCount() { + return sizeof($this->errors); + } + + /** + * Returns an Enumeration for the errors. + * + * @return array + * @access public + */ + public function errors() { + return $this->errors; + } + + /** + * Gets the number of detected failures. + * + * @return integer + * @access public + */ + public function failureCount() { + return sizeof($this->failures); + } + + /** + * Returns an Enumeration for the failures. + * + * @return array + * @access public + */ + public function failures() { + return $this->failures; + } + + /** + * Enables or disables the collection of Code Coverage information. + * + * @param boolean $flag + * @throws Exception + * @access public + * @since Method available since Release 2.3.0 + */ + public function collectCodeCoverageInformation($flag) { + if (is_bool($flag)) { + $this->collectCodeCoverageInformation = $flag; + } else { + throw new Exception; + } + } + + /** + * Returns Code Coverage data per test case. + * + * Format of the result array: + * + * + * array( + * "testCase" => array( + * "/tested/code.php" => array( + * linenumber => flag + * ) + * ) + * ) + * + * + * flag < 0: Line is executable but was not executed. + * flag > 0: Line was executed. + * + * @return array + * @access public + */ + public function getCodeCoverageInformation() { + return $this->codeCoverageInformation; + } + + /** + * Runs a TestCase. + * + * @param PHPUnit2_Framework_Test $test + * @access public + */ + public function run(PHPUnit2_Framework_Test $test) { + $this->startTest($test); + + set_error_handler('PHPUnit2_Util_ErrorHandler', E_USER_ERROR); + + $useXdebug = (extension_loaded('xdebug') && $this->collectCodeCoverageInformation); + + if ($useXdebug) { + xdebug_start_code_coverage(XDEBUG_CC_UNUSED); + } + + $globalsBackup = $GLOBALS; + + try { + $test->runBare(); + } + + catch (PHPUnit2_Framework_AssertionFailedError $e) { + $this->addFailure($test, $e); + } + + catch (Exception $e) { + $this->addError($test, $e); + } + + $GLOBALS = $globalsBackup; + + if ($useXdebug) { + $this->codeCoverageInformation[$test->getName()] = PHPUnit2_Util_Filter::getFilteredCodeCoverage( + xdebug_get_code_coverage() + ); + + xdebug_stop_code_coverage(); + } + + restore_error_handler(); + + $this->endTest($test); + } + + /** + * Gets the number of run tests. + * + * @return integer + * @access public + */ + public function runCount() { + return $this->runTests; + } + + /** + * Checks whether the test run should stop. + * + * @return boolean + * @access public + */ + public function shouldStop() { + return $this->stop; + } + + /** + * Marks that the test run should stop. + * + * @access public + */ + public function stop() { + $this->stop = TRUE; + } + + /** + * Returns whether the entire test was successful or not. + * + * @return boolean + * @access public + */ + public function wasSuccessful() { + return empty($this->errors) && empty($this->failures); + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Framework/TestSuite.php b/buildscripts/PHPUnit2/Framework/TestSuite.php new file mode 100644 index 00000000..3d5d670e --- /dev/null +++ b/buildscripts/PHPUnit2/Framework/TestSuite.php @@ -0,0 +1,554 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: TestSuite.php,v 1.26.2.11 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +require_once 'PHPUnit2/Framework/Test.php'; +require_once 'PHPUnit2/Framework/TestCase.php'; +require_once 'PHPUnit2/Framework/TestResult.php'; +require_once 'PHPUnit2/Runner/BaseTestRunner.php'; +require_once 'PHPUnit2/Util/Fileloader.php'; + +/** + * A TestSuite is a composite of Tests. It runs a collection of test cases. + * + * Here is an example using the dynamic test definition. + * + * + * addTest(new MathTest('testPass')); + * ?> + * + * + * Alternatively, a TestSuite can extract the tests to be run automatically. + * To do so you pass a ReflectionClass instance for your + * PHPUnit2_Framework_TestCase class to the PHPUnit2_Framework_TestSuite + * constructor. + * + * + * + * + * + * This constructor creates a suite with all the methods starting with + * "test" that take no arguments. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + */ +class PHPUnit2_Framework_TestSuite implements PHPUnit2_Framework_Test { + /** + * The name of the test suite. + * + * @var string + * @access private + */ + private $name = ''; + + /** + * The tests in the test suite. + * + * @var array + * @access private + */ + private $tests = array(); + + /** + * Constructs a new TestSuite: + * + * - PHPUnit2_Framework_TestSuite() constructs an empty TestSuite. + * + * - PHPUnit2_Framework_TestSuite(ReflectionClass) constructs a + * TestSuite from the given class. + * + * - PHPUnit2_Framework_TestSuite(ReflectionClass, String) + * constructs a TestSuite from the given class with the given + * name. + * + * - PHPUnit2_Framework_TestSuite(String) either constructs a + * TestSuite from the given class (if the passed string is the + * name of an existing class) or constructs an empty TestSuite + * with the given name. + * + * @param mixed $theClass + * @param string $name + * @throws Exception + * @access public + */ + public function __construct($theClass = '', $name = '') { + $argumentsValid = FALSE; + + if (is_object($theClass) && + $theClass instanceof ReflectionClass) { + $argumentsValid = TRUE; + } + + else if (is_string($theClass) && $theClass !== '' && class_exists($theClass)) { + $argumentsValid = TRUE; + + if ($name == '') { + $name = $theClass; + } + + $theClass = new ReflectionClass($theClass); + } + + else if (is_string($theClass)) { + $this->setName($theClass); + return; + } + + if (!$argumentsValid) { + throw new Exception; + } + + if ($name != '') { + $this->setName($name); + } else { + $this->setName($theClass->getName()); + } + + $constructor = $theClass->getConstructor(); + + if ($constructor === NULL || + !$constructor->isPublic()) { + $this->addTest( + self::warning( + sprintf( + 'Class %s has no public constructor', + + $theClass->getName() + ) + ) + ); + + return; + } + + $methods = $theClass->getMethods(); + $names = array(); + + foreach ($methods as $method) { + $this->addTestMethod($method, $names, $theClass); + } + + if (empty($this->tests)) { + $this->addTest( + self::warning( + sprintf( + 'No tests found in %s', + + $theClass->getName() + ) + ) + ); + } + } + + /** + * Returns a string representation of the test suite. + * + * @return string + * @access public + */ + public function toString() { + return $this->getName(); + } + + /** + * Adds a test to the suite. + * + * @param PHPUnit2_Framework_Test $test + * @access public + */ + public function addTest(PHPUnit2_Framework_Test $test) { + $this->tests[] = $test; + } + + /** + * Adds the tests from the given class to the suite. + * + * @param mixed $testClass + * @access public + */ + public function addTestSuite($testClass) { + if (is_string($testClass) && + class_exists($testClass)) { + $testClass = new ReflectionClass($testClass); + } + + if (is_object($testClass) && + $testClass instanceof ReflectionClass) { + $this->addTest(new PHPUnit2_Framework_TestSuite($testClass)); + } + } + + /** + * Wraps both addTest() and addTestSuite + * as well as the separate import statements for the user's convenience. + * + * If the named file cannot be read or there are no new tests that can be + * added, a PHPUnit2_Framework_Warning will be created instead, + * leaving the current test run untouched. + * + * @param string $filename + * @throws Exception + * @access public + * @since Method available since Release 2.3.0 + * @author Stefano F. Rausch + */ + public function addTestFile($filename) { + if (!is_string($filename) || !file_exists($filename)) { + throw new Exception; + } + + $declaredClasses = get_declared_classes(); + + PHPUnit2_Util_Fileloader::checkAndLoad($filename); + + $newClasses = array_values( + array_diff(get_declared_classes(), $declaredClasses) + ); + + $testsFound = 0; + + foreach ($newClasses as $class) { + if (preg_match('"Tests?$"', $class)) { + try { + $suiteMethod = new ReflectionMethod( + $class, PHPUnit2_Runner_BaseTestRunner::SUITE_METHODNAME + ); + + $this->addTest($suiteMethod->invoke(NULL)); + } catch (ReflectionException $e) { + $this->addTestSuite(new ReflectionClass($class)); + } + + $testsFound++; + } + } + + if ($testsFound == 0) { + $this->addTest( + new PHPUnit2_Framework_Warning('No tests found in file ' . $filename) + ); + } + } + + /** + * Wrapper for addTestFile() that adds multiple test files. + * + * @param Array $filenames + * @throws Exception + * @access public + * @since Method available since Release 2.3.0 + */ + public function addTestFiles($filenames) { + foreach ($filenames as $filename) { + $this->addTestFile($filename); + } + } + + /** + * Counts the number of test cases that will be run by this test. + * + * @return integer + * @access public + */ + public function countTestCases() { + $count = 0; + + foreach ($this->tests as $test) { + $count += $test->countTestCases(); + } + + return $count; + } + + /** + * @param ReflectionClass $theClass + * @param string $name + * @return PHPUnit2_Framework_Test + * @access public + * @static + */ + public static function createTest(ReflectionClass $theClass, $name) { + if (!$theClass->isInstantiable()) { + return self::warning( + sprintf( + 'Cannot instantiate test case %s.', + $theClass->getName() + ) + ); + } + + $constructor = $theClass->getConstructor(); + + if ($constructor !== NULL) { + $parameters = $constructor->getParameters(); + + if (sizeof($parameters) == 0) { + $test = $theClass->newInstance(); + + if ($test instanceof PHPUnit2_Framework_TestCase) { + $test->setName($name); + } + } + + else if (sizeof($parameters) == 1 && + $parameters[0]->getClass() === NULL) { + $test = $theClass->newInstance($name); + } + + else { + return self::warning( + sprintf( + 'Constructor of class %s is not TestCase($name) or TestCase().', + $theClass->getName() + ) + ); + } + } + + return $test; + } + + /** + * Creates a default TestResult object. + * + * @return PHPUnit2_Framework_TestResult + * @access protected + */ + protected function createResult() { + return new PHPUnit2_Framework_TestResult; + } + + /** + * Returns the name of the suite. + * + * @return string + * @access public + */ + public function getName() { + return $this->name; + } + + /** + * Runs the tests and collects their result in a TestResult. + * + * @param PHPUnit2_Framework_TestResult $result + * @return PHPUnit2_Framework_TestResult + * @throws Exception + * @access public + */ + public function run($result = NULL) { + if ($result === NULL) { + $result = $this->createResult(); + } + + // XXX: Workaround for missing ability to declare type-hinted parameters as optional. + else if (!($result instanceof PHPUnit2_Framework_TestResult)) { + throw new Exception( + 'Argument 1 must be an instance of PHPUnit2_Framework_TestResult.' + ); + } + + $result->startTestSuite($this); + + foreach ($this->tests as $test) { + if ($result->shouldStop()) { + break; + } + + $this->runTest($test, $result); + } + + $result->endTestSuite($this); + + return $result; + } + + /** + * Runs a test. + * + * @param PHPUnit2_Framework_Test $test + * @param PHPUnit2_Framework_TestResult $testResult + * @access public + */ + public function runTest(PHPUnit2_Framework_Test $test, PHPUnit2_Framework_TestResult $result) { + $test->run($result); + } + + /** + * Sets the name of the suite. + * + * @param string + * @access public + */ + public function setName($name) { + $this->name = $name; + } + + /** + * Returns the test at the given index. + * + * @param integer + * @return PHPUnit2_Framework_Test + * @access public + */ + public function testAt($index) { + if (isset($this->tests[$index])) { + return $this->tests[$index]; + } else { + return FALSE; + } + } + + /** + * Returns the number of tests in this suite. + * + * @return integer + * @access public + */ + public function testCount() { + return sizeof($this->tests); + } + + /** + * Returns the tests as an enumeration. + * + * @return array + * @access public + */ + public function tests() { + return $this->tests; + } + + /** + * @param ReflectionMethod $method + * @param array $names + * @param ReflectionClass $theClass + * @access private + */ + private function addTestMethod(ReflectionMethod $method, &$names, ReflectionClass $theClass) { + $name = $method->getName(); + + if (in_array($name, $names)) { + return; + } + + if ($this->isPublicTestMethod($method)) { + $names[] = $name; + + $this->addTest( + self::createTest( + $theClass, + $name + ) + ); + } + + else if ($this->isTestMethod($method)) { + $this->addTest( + self::warning( + sprintf( + 'Test method is not public: %s', + + $name + ) + ) + ); + } + } + + /** + * @param ReflectionMethod $method + * @return boolean + * @access private + */ + private function isPublicTestMethod(ReflectionMethod $method) { + return ($this->isTestMethod($method) && + $method->isPublic()); + } + + /** + * @param ReflectionMethod $method + * @return boolean + * @access private + */ + private function isTestMethod(ReflectionMethod $method) { + return (substr($method->name, 0, 4) == 'test'); + } + + /** + * @param string $message + * @return PHPUnit2_Framework_Warning + * @access private + */ + private static function warning($message) { + require_once 'PHPUnit2/Framework/Warning.php'; + return new PHPUnit2_Framework_Warning($message); + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Framework/Warning.php b/buildscripts/PHPUnit2/Framework/Warning.php new file mode 100644 index 00000000..0ae885a4 --- /dev/null +++ b/buildscripts/PHPUnit2/Framework/Warning.php @@ -0,0 +1,94 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: Warning.php,v 1.11.2.3 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +require_once 'PHPUnit2/Framework/TestCase.php'; + +/** + * A warning. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + */ +class PHPUnit2_Framework_Warning extends PHPUnit2_Framework_TestCase { + /** + * @var string + * @access private + */ + private $message = ''; + + /** + * @param string $message + * @access public + */ + public function __construct($message = '') { + $this->message = $message; + parent::__construct('Warning'); + } + + /** + * @access protected + */ + protected function runTest() { + $this->fail($this->message); + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Runner/BaseTestRunner.php b/buildscripts/PHPUnit2/Runner/BaseTestRunner.php new file mode 100644 index 00000000..b9517e5a --- /dev/null +++ b/buildscripts/PHPUnit2/Runner/BaseTestRunner.php @@ -0,0 +1,283 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: BaseTestRunner.php,v 1.18.2.3 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +require_once 'PHPUnit2/Framework/AssertionFailedError.php'; +require_once 'PHPUnit2/Framework/TestListener.php'; +require_once 'PHPUnit2/Runner/StandardTestSuiteLoader.php'; + +/** + * Base class for all test runners. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + * @abstract + */ +abstract class PHPUnit2_Runner_BaseTestRunner implements PHPUnit2_Framework_TestListener { + const STATUS_ERROR = 1; + const STATUS_FAILURE = 2; + const STATUS_INCOMPLETE = 3; + const SUITE_METHODNAME = 'suite'; + + /** + * An error occurred. + * + * @param PHPUnit2_Framework_Test $test + * @param Exception $e + * @access public + */ + public function addError(PHPUnit2_Framework_Test $test, Exception $e) { + $this->testFailed(self::STATUS_ERROR, $test, $e); + } + + /** + * A failure occurred. + * + * @param PHPUnit2_Framework_Test $test + * @param PHPUnit2_Framework_AssertionFailedError $e + * @access public + */ + public function addFailure(PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $e) { + $this->testFailed(self::STATUS_FAILURE, $test, $e); + } + + /** + * Incomplete test. + * + * @param PHPUnit2_Framework_Test $test + * @param Exception $e + * @access public + */ + public function addIncompleteTest(PHPUnit2_Framework_Test $test, Exception $e) { + $this->testFailed(self::STATUS_INCOMPLETE, $test, $e); + } + + /** + * A testsuite started. + * + * @param PHPUnit2_Framework_TestSuite $suite + * @access public + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit2_Framework_TestSuite $suite) { + } + + /** + * A testsuite ended. + * + * @param PHPUnit2_Framework_TestSuite $suite + * @access public + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit2_Framework_TestSuite $suite) { + } + + /** + * A test started. + * + * @param PHPUnit2_Framework_Test $test + * @access public + */ + public function startTest(PHPUnit2_Framework_Test $test) { + $this->testStarted($test->getName()); + } + + /** + * A test ended. + * + * @param PHPUnit2_Framework_Test $test + * @access public + */ + public function endTest(PHPUnit2_Framework_Test $test) { + $this->testEnded($test->getName()); + } + + /** + * Returns the loader to be used. + * + * @return PHPUnit2_Runner_TestSuiteLoader + * @access public + */ + public function getLoader() { + return new PHPUnit2_Runner_StandardTestSuiteLoader; + } + + /** + * Returns the Test corresponding to the given suite. + * This is a template method, subclasses override + * the runFailed() and clearStatus() methods. + * + * @param string $suiteClassName + * @param string $suiteClassFile + * @return PHPUnit2_Framework_Test + * @access public + */ + public function getTest($suiteClassName, $suiteClassFile = '') { + if ($suiteClassFile == $suiteClassName . '.php') { + $suiteClassFile = ''; + } + + try { + $testClass = $this->loadSuiteClass($suiteClassName, $suiteClassFile); + } + + catch (Exception $e) { + $this->runFailed($e->getMessage()); + return NULL; + } + + try { + $suiteMethod = $testClass->getMethod(self::SUITE_METHODNAME); + + if (!$suiteMethod->isStatic()) { + $this->runFailed( + 'suite() method must be static.' + ); + + return NULL; + } + + try { + $test = $suiteMethod->invoke(NULL); + } + + catch (ReflectionException $e) { + $this->runFailed( + sprintf( + "Failed to invoke suite() method.\n%s", + + $e->getMessage() + ) + ); + + return NULL; + } + } + + catch (ReflectionException $e) { + $test = new PHPUnit2_Framework_TestSuite($testClass); + } + + $this->clearStatus(); + + return $test; + } + + /** + * Override to define how to handle a failed loading of + * a test suite. + * + * @param string $message + * @access protected + * @abstract + */ + protected abstract function runFailed($message); + + /** + * Returns the loaded ReflectionClass for a suite name. + * + * @param string $suiteClassName + * @param string $suiteClassFile + * @return ReflectionClass + * @access protected + */ + protected function loadSuiteClass($suiteClassName, $suiteClassFile = '') { + return $this->getLoader()->load($suiteClassName, $suiteClassFile); + } + + /** + * Clears the status message. + * + * @access protected + */ + protected function clearStatus() { + } + + /** + * A test started. + * + * @param string $testName + * @access public + * @abstract + */ + public abstract function testStarted($testName); + + /** + * A test ended. + * + * @param string $testName + * @access public + * @abstract + */ + public abstract function testEnded($testName); + + /** + * A test failed. + * + * @param integer $status + * @param PHPUnit2_Framework_Test $test + * @param PHPUnit2_Framework_AssertionFailedError $e + * @access public + * @abstract + */ + public abstract function testFailed($status, PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $e); +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Runner/IncludePathTestCollector.php b/buildscripts/PHPUnit2/Runner/IncludePathTestCollector.php new file mode 100644 index 00000000..116b20ed --- /dev/null +++ b/buildscripts/PHPUnit2/Runner/IncludePathTestCollector.php @@ -0,0 +1,184 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: IncludePathTestCollector.php,v 1.13.2.5 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.1.0 + */ + +if (!class_exists('AppendIterator')) { + class AppendIterator implements Iterator { + private $iterators; + + public function __construct() { + $this->iterators = new ArrayIterator(); + } + + public function __call($func, $params) { + return call_user_func_array(array($this->getInnerIterator(), $func), $params); + } + + public function append(Iterator $it) { + $this->iterators->append($it); + } + + public function getInnerIterator() { + return $this->iterators->current(); + } + + public function rewind() { + $this->iterators->rewind(); + + if ($this->iterators->valid()) { + $this->getInnerIterator()->rewind(); + } + } + + public function valid() { + return $this->iterators->valid() && $this->getInnerIterator()->valid(); + } + + public function current() { + return $this->iterators->valid() ? $this->getInnerIterator()->current() : NULL; + } + + public function key() { + return $this->iterators->valid() ? $this->getInnerIterator()->key() : NULL; + } + + public function next() { + if (!$this->iterators->valid()) return; + $this->getInnerIterator()->next(); + + if ($this->getInnerIterator()->valid()) return; + $this->iterators->next(); + + while ($this->iterators->valid()) { + $this->getInnerIterator()->rewind(); + + if ($this->getInnerIterator()->valid()) return; + $this->iterators->next(); + } + } + } +} + +require_once 'PHPUnit2/Runner/TestCollector.php'; + +require_once 'PEAR/Config.php'; + +/** + * An implementation of a TestCollector that consults the + * include path set in the php.ini. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.1.0 + */ + +class PHPUnit2_Runner_IncludePathTestCollector implements PHPUnit2_Runner_TestCollector { + /** + * @return array + * @access public + */ + public function collectTests() { + $config = new PEAR_Config; + $iterator = new AppendIterator; + $result = array(); + + if (substr(PHP_OS, 0, 3) == 'WIN') { + $delimiter = ';'; + } else { + $delimiter = ':'; + } + + $paths = explode($delimiter, ini_get('include_path')); + $paths[] = $config->get('test_dir'); + + foreach ($paths as $path) { + $iterator->append( + new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($path) + ) + ); + } + + foreach ($iterator as $path => $file) { + if ($this->isTestClass($file)) { + if (substr(PHP_OS, 0, 3) == 'WIN') { + $path = str_replace('/', '\\', $path); + } + + $result[] = $path; + } + } + + return $result; + } + + /** + * Considers a file to contain a test class when it contains the + * pattern "Test" in its name and its name ends with ".php". + * + * @param string $classFileName + * @return boolean + * @access protected + */ + protected function isTestClass($classFileName) { + return (strpos($classFileName, 'Test') !== FALSE && substr($classFileName, -4) == '.php') ? TRUE : FALSE; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Runner/StandardTestSuiteLoader.php b/buildscripts/PHPUnit2/Runner/StandardTestSuiteLoader.php new file mode 100644 index 00000000..b0c359a0 --- /dev/null +++ b/buildscripts/PHPUnit2/Runner/StandardTestSuiteLoader.php @@ -0,0 +1,129 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: StandardTestSuiteLoader.php,v 1.19.2.8 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +require_once 'PHPUnit2/Runner/TestSuiteLoader.php'; +require_once 'PHPUnit2/Util/Fileloader.php'; + +require_once 'PEAR/Config.php'; + +/** + * The standard test suite loader. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + */ +class PHPUnit2_Runner_StandardTestSuiteLoader implements PHPUnit2_Runner_TestSuiteLoader { + /** + * @param string $suiteClassName + * @param string $suiteClassFile + * @return ReflectionClass + * @throws Exception + * @access public + */ + public function load($suiteClassName, $suiteClassFile = '') { + $suiteClassName = str_replace('.php', '', $suiteClassName); + $suiteClassFile = !empty($suiteClassFile) ? $suiteClassFile : str_replace('_', '/', $suiteClassName) . '.php'; + + if (!class_exists($suiteClassName)) { + if(!file_exists($suiteClassFile)) { + $config = new PEAR_Config; + + $includePaths = explode(PATH_SEPARATOR, get_include_path()); + $includePaths[] = $config->get('test_dir'); + + foreach ($includePaths as $includePath) { + $file = $includePath . DIRECTORY_SEPARATOR . $suiteClassFile; + + if (file_exists($file)) { + $suiteClassFile = $file; + break; + } + } + } + + PHPUnit2_Util_Fileloader::checkAndLoad($suiteClassFile); + } + + if (class_exists($suiteClassName)) { + return new ReflectionClass($suiteClassName); + } else { + throw new Exception( + sprintf( + 'Class %s could not be found in %s.', + + $suiteClassName, + $suiteClassFile + ) + ); + } + } + + /** + * @param ReflectionClass $aClass + * @return ReflectionClass + * @access public + */ + public function reload(ReflectionClass $aClass) { + return $aClass; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Runner/TestCollector.php b/buildscripts/PHPUnit2/Runner/TestCollector.php new file mode 100644 index 00000000..38a9ce81 --- /dev/null +++ b/buildscripts/PHPUnit2/Runner/TestCollector.php @@ -0,0 +1,77 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: TestCollector.php,v 1.7.2.2 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +/** + * Collects Test class names to be presented + * by the TestSelector. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Interface available since Release 2.0.0 + */ +interface PHPUnit2_Runner_TestCollector { + /** + * @return array + * @access public + */ + public function collectTests(); +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Runner/TestSuiteLoader.php b/buildscripts/PHPUnit2/Runner/TestSuiteLoader.php new file mode 100644 index 00000000..711a03d2 --- /dev/null +++ b/buildscripts/PHPUnit2/Runner/TestSuiteLoader.php @@ -0,0 +1,85 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: TestSuiteLoader.php,v 1.11.2.2 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +/** + * An interface to define how a test suite should be loaded. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Interface available since Release 2.0.0 + */ +interface PHPUnit2_Runner_TestSuiteLoader { + /** + * @param string $suiteClassName + * @param string $suiteClassFile + * @return ReflectionClass + * @access public + */ + public function load($suiteClassName, $suiteClassFile = ''); + + /** + * @param ReflectionClass $aClass + * @return ReflectionClass + * @access public + */ + public function reload(ReflectionClass $aClass); +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Runner/Version.php b/buildscripts/PHPUnit2/Runner/Version.php new file mode 100644 index 00000000..5a0f7785 --- /dev/null +++ b/buildscripts/PHPUnit2/Runner/Version.php @@ -0,0 +1,90 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: Version.php,v 1.7.2.2 2005/12/17 16:04:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +/** + * This class defines the current version of PHPUnit. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + */ +class PHPUnit2_Runner_Version { + /** + * Returns the current version of PHPUnit. + * + * @return string + * @access public + * @static + */ + public static function id() { + return '@package_version@'; + } + + /** + * @return string + * @access public + * @static + */ + public static function getVersionString() { + return 'PHPUnit @package_version@ by Sebastian Bergmann.'; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/TextUI/ResultPrinter.php b/buildscripts/PHPUnit2/TextUI/ResultPrinter.php new file mode 100644 index 00000000..32d3e667 --- /dev/null +++ b/buildscripts/PHPUnit2/TextUI/ResultPrinter.php @@ -0,0 +1,356 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: ResultPrinter.php,v 1.20.2.5 2005/12/17 16:04:57 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +require_once 'PHPUnit2/Framework/TestListener.php'; +require_once 'PHPUnit2/Framework/TestFailure.php'; +require_once 'PHPUnit2/Util/Filter.php'; +require_once 'PHPUnit2/Util/Printer.php'; + +/** + * Prints the result of a TextUI TestRunner run. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + */ +class PHPUnit2_TextUI_ResultPrinter extends PHPUnit2_Util_Printer implements PHPUnit2_Framework_TestListener { + /** + * @var integer + * @access private + */ + private $column = 0; + + /** + * @var boolean + * @access private + */ + private $lastTestFailed = FALSE; + + /** + * @param PHPUnit2_Framework_TestResult $result + * @param float $runTime + * @access public + */ + public function printResult(PHPUnit2_Framework_TestResult $result, $timeElapsed) { + $this->printHeader($timeElapsed); + $this->printErrors($result); + $this->printFailures($result); + $this->printIncompletes($result); + $this->printFooter($result); + } + + /** + * @param array $defects + * @param integer $count + * @param string $type + * @access protected + */ + protected function printDefects($defects, $count, $type) { + if ($count == 0) { + return; + } + + $this->write( + sprintf( + "There %s %d %s%s:\n", + + ($count == 1) ? 'was' : 'were', + $count, + $type, + ($count == 1) ? '' : 's' + ) + ); + + $i = 1; + + foreach ($defects as $defect) { + $this->printDefect($defect, $i++); + } + } + + /** + * @param PHPUnit2_Framework_TestFailure $defect + * @param integer $count + * @access protected + */ + protected function printDefect(PHPUnit2_Framework_TestFailure $defect, $count) { + $this->printDefectHeader($defect, $count); + $this->printDefectTrace($defect); + } + + /** + * @param PHPUnit2_Framework_TestFailure $defect + * @param integer $count + * @access protected + */ + protected function printDefectHeader(PHPUnit2_Framework_TestFailure $defect, $count) { + $this->write( + sprintf( + "%d) %s\n", + + $count, + $defect->failedTest()->toString() + ) + ); + } + + /** + * @param PHPUnit2_Framework_TestFailure $defect + * @access protected + */ + protected function printDefectTrace(PHPUnit2_Framework_TestFailure $defect) { + $e = $defect->thrownException(); + $message = method_exists($e, 'toString') ? $e->toString() : $e->getMessage(); + + $this->write($message . "\n"); + + $this->write( + PHPUnit2_Util_Filter::getFilteredStacktrace( + $defect->thrownException() + ) + ); + } + + /** + * @param PHPUnit2_Framework_TestResult $result + * @access protected + */ + protected function printErrors(PHPUnit2_Framework_TestResult $result) { + $this->printDefects($result->errors(), $result->errorCount(), 'error'); + } + + /** + * @param PHPUnit2_Framework_TestResult $result + * @access protected + */ + protected function printFailures(PHPUnit2_Framework_TestResult $result) { + $this->printDefects($result->failures(), $result->failureCount(), 'failure'); + } + + /** + * @param PHPUnit2_Framework_TestResult $result + * @access protected + */ + protected function printIncompletes(PHPUnit2_Framework_TestResult $result) { + $this->printDefects($result->notImplemented(), $result->notImplementedCount(), 'incomplete test case'); + } + + /** + * @param float $timeElapsed + * @access protected + */ + protected function printHeader($timeElapsed) { + $this->write( + sprintf( + "\n\nTime: %s\n", + + $timeElapsed + ) + ); + } + + /** + * @param PHPUnit2_Framework_TestResult $result + * @access protected + */ + protected function printFooter(PHPUnit2_Framework_TestResult $result) { + if ($result->allCompletlyImplemented() && + $result->wasSuccessful()) { + $this->write( + sprintf( + "\nOK (%d test%s)\n", + + $result->runCount(), + ($result->runCount() == 1) ? '' : 's' + ) + ); + } + + else if (!$result->allCompletlyImplemented() && + $result->wasSuccessful()) { + $this->write( + sprintf( + "\nOK, but incomplete test cases!!!\nTests run: %d, Incomplete Tests: %d.\n", + + $result->runCount(), + $result->notImplementedCount() + ) + ); + } + + else { + $this->write( + sprintf( + "\nFAILURES!!!\nTests run: %d, Failures: %d, Errors: %d, Incomplete Tests: %d.\n", + + $result->runCount(), + $result->failureCount(), + $result->errorCount(), + $result->notImplementedCount() + ) + ); + } + } + + /** + * @access public + */ + public function printWaitPrompt() { + $this->write("\n to continue\n"); + } + + /** + * An error occurred. + * + * @param PHPUnit2_Framework_Test $test + * @param Exception $e + * @access public + */ + public function addError(PHPUnit2_Framework_Test $test, Exception $e) { + $this->write('E'); + $this->nextColumn(); + + $this->lastTestFailed = TRUE; + } + + /** + * A failure occurred. + * + * @param PHPUnit2_Framework_Test $test + * @param PHPUnit2_Framework_AssertionFailedError $e + * @access public + */ + public function addFailure(PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $e) { + $this->write('F'); + $this->nextColumn(); + + $this->lastTestFailed = TRUE; + } + + /** + * Incomplete test. + * + * @param PHPUnit2_Framework_Test $test + * @param Exception $e + * @access public + */ + public function addIncompleteTest(PHPUnit2_Framework_Test $test, Exception $e) { + $this->write('I'); + $this->nextColumn(); + + $this->lastTestFailed = TRUE; + } + + /** + * A testsuite started. + * + * @param PHPUnit2_Framework_TestSuite $suite + * @access public + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit2_Framework_TestSuite $suite) { + } + + /** + * A testsuite ended. + * + * @param PHPUnit2_Framework_TestSuite $suite + * @access public + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit2_Framework_TestSuite $suite) { + } + + /** + * A test started. + * + * @param PHPUnit2_Framework_Test $test + * @access public + */ + public function startTest(PHPUnit2_Framework_Test $test) { + } + + /** + * A test ended. + * + * @param PHPUnit2_Framework_Test $test + * @access public + */ + public function endTest(PHPUnit2_Framework_Test $test) { + if (!$this->lastTestFailed) { + $this->write('.'); + $this->nextColumn(); + } + + $this->lastTestFailed = FALSE; + } + + /** + * @access protected + */ + protected function nextColumn() { + if ($this->column++ >= 40) { + $this->column = 0; + $this->write("\n"); + } + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/TextUI/TestRunner.php b/buildscripts/PHPUnit2/TextUI/TestRunner.php new file mode 100644 index 00000000..63639a24 --- /dev/null +++ b/buildscripts/PHPUnit2/TextUI/TestRunner.php @@ -0,0 +1,622 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: TestRunner.php,v 1.64.2.5 2005/12/17 16:04:58 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +if (!defined('PHPUnit2_MAIN_METHOD')) { + define('PHPUnit2_MAIN_METHOD', 'PHPUnit2_TextUI_TestRunner::main'); +} + +require_once 'PHPUnit2/Framework/TestSuite.php'; +require_once 'PHPUnit2/Runner/Version.php'; +require_once 'PHPUnit2/Runner/BaseTestRunner.php'; +require_once 'PHPUnit2/TextUI/ResultPrinter.php'; +require_once 'PHPUnit2/Util/Fileloader.php'; + +require_once 'Console/Getopt.php'; +require_once 'Benchmark/Timer.php'; + +/** + * A TestRunner for the Command Line Interface (CLI) + * PHP SAPI Module. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + */ +class PHPUnit2_TextUI_TestRunner extends PHPUnit2_Runner_BaseTestRunner { + const SUCCESS_EXIT = 0; + const FAILURE_EXIT = 1; + const EXCEPTION_EXIT = 2; + + /** + * @var PHPUnit2_Runner_TestSuiteLoader + * @access private + */ + private $loader = NULL; + + /** + * @var PHPUnit2_TextUI_ResultPrinter + * @access private + */ + private $printer = NULL; + + /** + * @var boolean + * @access private + * @static + */ + private static $versionStringPrinted = FALSE; + + /** + * @access public + * @static + */ + public static function main() { + $aTestRunner = new PHPUnit2_TextUI_TestRunner; + + try { + $result = $aTestRunner->start($_SERVER['argv']); + + if (!$result->wasSuccessful()) { + exit(self::FAILURE_EXIT); + } + + exit(self::SUCCESS_EXIT); + } + + catch (Exception $e) { + self::printVersionString(); + print $e->getMessage(); + exit(self::EXCEPTION_EXIT); + } + } + + /** + * @param array $arguments + * @throws Exception + * @access protected + */ + protected function start($arguments) { + $coverageDataFile = FALSE; + $coverageHTMLFile = FALSE; + $coverageTextFile = FALSE; + $testdoxHTMLFile = FALSE; + $testdoxTextFile = FALSE; + $xmlLogfile = FALSE; + $wait = FALSE; + + $possibleOptions = array( + 'help', + 'loader=', + 'log-xml=', + 'skeleton', + 'testdox-html=', + 'testdox-text=', + 'version', + 'wait' + ); + + if (extension_loaded('xdebug')) { + $possibleOptions[] = 'coverage-data='; + $possibleOptions[] = 'coverage-html='; + $possibleOptions[] = 'coverage-text='; + } + + $options = Console_Getopt::getopt( + $arguments, + '', + $possibleOptions + ); + + if (PEAR::isError($options)) { + $this->showError($options->getMessage()); + } + + $test = isset($options[1][0]) ? $options[1][0] : FALSE; + $testFile = isset($options[1][1]) ? $options[1][1] : $test . '.php'; + + foreach ($options[0] as $option) { + switch ($option[0]) { + case '--coverage-data': { + $coverageDataFile = $option[1]; + } + break; + + case '--coverage-html': { + $coverageHTMLFile = $option[1]; + } + break; + + case '--coverage-text': { + $coverageTextFile = $option[1]; + } + break; + + case '--help': { + $this->showHelp(); + exit(self::SUCCESS_EXIT); + } + break; + + case '--testdox-html': { + $testdoxHTMLFile = $option[1]; + } + break; + + case '--testdox-text': { + $testdoxTextFile = $option[1]; + } + break; + + case '--loader': { + if (!class_exists($option[1])) { + PHPUnit2_Util_Fileloader::checkAndLoad( + str_replace('_', '/', $option[1]) . '.php' + ); + } + + if (class_exists($option[1])) { + $class = new ReflectionClass($option[1]); + + if ($class->implementsInterface('PHPUnit2_Runner_TestSuiteLoader') && + $class->isInstantiable()) { + $this->loader = $class->newInstance(); + } + } + + if ($this->loader === NULL) { + $this->showError( + sprintf( + 'Could not use "%s" as loader.', + + $option[1] + ) + ); + } + } + break; + + case '--log-xml': { + $xmlLogfile = $option[1]; + } + break; + + case '--skeleton': { + if ($test !== FALSE) { + self::printVersionString(); + + try { + require_once 'PHPUnit2/Util/Skeleton.php'; + + $skeleton = new PHPUnit2_Util_Skeleton($test, $testFile); + $skeleton->write(); + } + + catch (Exception $e) { + print $e->getMessage() . "\n"; + + printf( + "Could not write test class skeleton for %s to %s.\n", + $test, + $test . 'Test.php' + ); + + exit(self::FAILURE_EXIT); + } + + printf( + "Wrote test class skeleton for %s to %s.\n", + $test, + $test . 'Test.php' + ); + + exit(self::SUCCESS_EXIT); + } + } + break; + + case '--version': { + self::printVersionString(); + exit(self::SUCCESS_EXIT); + } + break; + + case '--wait': { + $wait = TRUE; + } + break; + } + } + + if ($test === FALSE) { + $this->showHelp(); + + exit(self::SUCCESS_EXIT); + } + + try { + return $this->doRun( + $this->getTest($test, $testFile), + $coverageDataFile, + $coverageHTMLFile, + $coverageTextFile, + $testdoxHTMLFile, + $testdoxTextFile, + $xmlLogfile, + $wait + ); + } + + catch (Exception $e) { + throw new Exception( + 'Could not create and run test suite: ' . $e->getMessage() + ); + } + } + + /** + * @param mixed $test + * @param mixed $coverageDataFile + * @param mixed $testdoxHTMLFile + * @param mixed $testdoxTextFile + * @param mixed $xmlLogfile + * @param boolean $wait + * @access public + * @static + */ + public static function run($test, $coverageDataFile = FALSE, $coverageHTMLFile = FALSE, $coverageTextFile = FALSE, $testdoxHTMLFile = FALSE, $testdoxTextFile = FALSE, $xmlLogfile = FALSE, $wait = FALSE) { + if ($test instanceof ReflectionClass) { + $test = new PHPUnit2_Framework_TestSuite($test); + } + + if ($test instanceof PHPUnit2_Framework_Test) { + $aTestRunner = new PHPUnit2_TextUI_TestRunner; + + return $aTestRunner->doRun( + $test, + $coverageDataFile, + $coverageHTMLFile, + $coverageTextFile, + $testdoxHTMLFile, + $testdoxTextFile, + $xmlLogfile, + $wait + ); + } + } + + /** + * Runs a single test and waits until the user types RETURN. + * + * @param PHPUnit2_Framework_Test $suite + * @access public + * @static + */ + public static function runAndWait(PHPUnit2_Framework_Test $suite) { + $aTestRunner = new PHPUnit2_TextUI_TestRunner; + + $aTestRunner->doRun( + $suite, + FALSE, + FALSE, + FALSE, + FALSE, + FALSE, + FALSE, + TRUE + ); + } + + /** + * @return PHPUnit2_Framework_TestResult + * @access protected + */ + protected function createTestResult() { + return new PHPUnit2_Framework_TestResult; + } + + /** + * @param PHPUnit2_Framework_Test $suite + * @param mixed $coverageDataFile + * @param mixed $coverageHTMLFile + * @param mixed $coverageTextFile + * @param mixed $testdoxHTMLFile + * @param mixed $testdoxTextFile + * @param mixed $xmlLogfile + * @param boolean $wait + * @return PHPUnit2_Framework_TestResult + * @access public + */ + public function doRun(PHPUnit2_Framework_Test $suite, $coverageDataFile = FALSE, $coverageHTMLFile = FALSE, $coverageTextFile = FALSE, $testdoxHTMLFile = FALSE, $testdoxTextFile = FALSE, $xmlLogfile = FALSE, $wait = FALSE) { + $result = $this->createTestResult(); + $timer = new Benchmark_Timer; + + if ($this->printer === NULL) { + $this->printer = new PHPUnit2_TextUI_ResultPrinter; + } + + $this->printer->write( + PHPUnit2_Runner_Version::getVersionString() . "\n\n" + ); + + $result->addListener($this->printer); + + if ($testdoxHTMLFile !== FALSE || $testdoxTextFile !== FALSE) { + require_once 'PHPUnit2/Util/TestDox/ResultPrinter.php'; + + if ($testdoxHTMLFile !== FALSE) { + $result->addListener( + PHPUnit2_Util_TestDox_ResultPrinter::factory( + 'HTML', + $testdoxHTMLFile + ) + ); + } + + if ($testdoxTextFile !== FALSE) { + $result->addListener( + PHPUnit2_Util_TestDox_ResultPrinter::factory( + 'Text', + $testdoxTextFile + ) + ); + } + } + + if ($xmlLogfile !== FALSE) { + require_once 'PHPUnit2/Util/Log/XML.php'; + + $result->addListener( + new PHPUnit2_Util_Log_XML($xmlLogfile) + ); + } + + if ($coverageDataFile !== FALSE || + $coverageHTMLFile !== FALSE || + $coverageTextFile !== FALSE) { + $result->collectCodeCoverageInformation(TRUE); + } + + $timer->start(); + $suite->run($result); + $timer->stop(); + $timeElapsed = $timer->timeElapsed(); + + $this->pause($wait); + + $this->printer->printResult($result, $timeElapsed); + + $this->handleCodeCoverageInformation( + $result, + $coverageDataFile, + $coverageHTMLFile, + $coverageTextFile + ); + + return $result; + } + + /** + * Returns the loader to be used. + * + * @return PHPUnit2_Runner_TestSuiteLoader + * @access public + * @since Method available since Release 2.2.0 + */ + public function getLoader() { + if ($this->loader === NULL) { + $this->loader = new PHPUnit2_Runner_StandardTestSuiteLoader; + } + + return $this->loader; + } + + /** + * @param PHPUnit2_Framework_TestResult $result + * @param mixed $coverageDataFile + * @param mixed $coverageHTMLFile + * @param mixed $coverageTextFile + * @access protected + * @since Method available since Release 2.1.0 + */ + protected function handleCodeCoverageInformation(PHPUnit2_Framework_TestResult $result, $coverageDataFile, $coverageHTMLFile, $coverageTextFile) { + if ($coverageDataFile !== FALSE && + $fp = fopen($coverageDataFile, 'w')) { + fputs($fp, serialize($result->getCodeCoverageInformation())); + fclose($fp); + } + + if ($coverageHTMLFile !== FALSE || $coverageTextFile !== FALSE) { + require_once 'PHPUnit2/Util/CodeCoverage/Renderer.php'; + + if ($coverageHTMLFile !== FALSE) { + $renderer = PHPUnit2_Util_CodeCoverage_Renderer::factory( + 'HTML', + $result->getCodeCoverageInformation() + ); + + $renderer->renderToFile($coverageHTMLFile); + } + + if ($coverageTextFile !== FALSE) { + $renderer = PHPUnit2_Util_CodeCoverage_Renderer::factory( + 'Text', + $result->getCodeCoverageInformation() + ); + + $renderer->renderToFile($coverageTextFile); + } + } + } + + /** + * @access public + */ + public function showError($message) { + self::printVersionString(); + print $message . "\n"; + + exit(self::FAILURE_EXIT); + } + + /** + * @access public + */ + public function showHelp() { + self::printVersionString(); + print "Usage: phpunit [switches] UnitTest [UnitTest.php]\n"; + + if (extension_loaded('xdebug')) { + print " --coverage-data Write Code Coverage data in raw format to file.\n" . + " --coverage-html Write Code Coverage data in HTML format to file.\n" . + " --coverage-text Write Code Coverage data in text format to file.\n\n"; + } + + print " --testdox-html Write agile documentation in HTML format to file.\n" . + " --testdox-text Write agile documentation in Text format to file.\n" . + " --log-xml Log test progress in XML format to file.\n\n"; + + print " --loader TestSuiteLoader implementation to use.\n\n" . + " --skeleton Generate skeleton UnitTest class for Unit in Unit.php.\n\n" . + " --wait Waits for a keystroke after each test.\n\n" . + " --help Prints this usage information.\n" . + " --version Prints the version and exits.\n"; + } + + /** + * @param boolean $wait + * @access protected + */ + protected function pause($wait) { + if (!$wait) { + return; + } + + $this->printer->printWaitPrompt(); + + fgets(STDIN); + } + + /** + * @param PHPUnit2_TextUI_ResultPrinter $resultPrinter + * @access public + */ + public function setPrinter(PHPUnit2_TextUI_ResultPrinter $resultPrinter) { + $this->printer = $resultPrinter; + } + + /** + * A test started. + * + * @param string $testName + * @access public + */ + public function testStarted($testName) { + } + + /** + * A test ended. + * + * @param string $testName + * @access public + */ + public function testEnded($testName) { + } + + /** + * A test failed. + * + * @param integer $status + * @param PHPUnit2_Framework_Test $test + * @param PHPUnit2_Framework_AssertionFailedError $e + * @access public + */ + public function testFailed($status, PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $e) { + } + + /** + * Override to define how to handle a failed loading of + * a test suite. + * + * @param string $message + * @access protected + */ + protected function runFailed($message) { + self::printVersionString(); + print $message; + exit(self::FAILURE_EXIT); + } + + /** + * @access private + * @since Method available since Release 2.2.0 + */ + private static function printVersionString() { + if (!self::$versionStringPrinted) { + print PHPUnit2_Runner_Version::getVersionString() . "\n\n"; + self::$versionStringPrinted = TRUE; + } + } +} + +if (PHPUnit2_MAIN_METHOD == 'PHPUnit2_TextUI_TestRunner::main') { + PHPUnit2_TextUI_TestRunner::main(); +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Util/CodeCoverage/Renderer.php b/buildscripts/PHPUnit2/Util/CodeCoverage/Renderer.php new file mode 100644 index 00000000..cbcdda51 --- /dev/null +++ b/buildscripts/PHPUnit2/Util/CodeCoverage/Renderer.php @@ -0,0 +1,225 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: Renderer.php,v 1.8.2.7 2006/02/25 17:02:23 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.3.0 + */ + +/** + * Abstract base class for Code Coverage renderers. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.1.0 + * @abstract + */ +abstract class PHPUnit2_Util_CodeCoverage_Renderer { + /** + * @var array + * @access protected + */ + protected $codeCoverageInformation; + + /** + * Constructor. + * + * @param array $codeCoverageInformation + * @access protected + */ + protected function __construct($codeCoverageInformation) { + $this->codeCoverageInformation = $codeCoverageInformation; + } + + /** + * Abstract Factory. + * + * @param string $rendererName + * @param array $codeCoverageInformation + * @throws Exception + * @access public + */ + public function factory($rendererName, $codeCoverageInformation) { + require_once 'PHPUnit2/Util/CodeCoverage/Renderer/' . $rendererName . '.php'; + + $class = 'PHPUnit2_Util_CodeCoverage_Renderer_' . $rendererName; + return new $class($codeCoverageInformation); + } + + /** + * Visualizes the result array of + * PHPUnit2_Framework_TestResult::getCodeCoverageInformation(). + * + * @return string + * @access public + * @final + */ + public final function render() { + $buffer = $this->header(); + + foreach ($this->getSummary() as $sourceFile => $executedLines) { + if (file_exists($sourceFile)) { + $buffer .= $this->startSourceFile($sourceFile); + $buffer .= $this->renderSourceFile(file($sourceFile), $executedLines); + $buffer .= $this->endSourceFile($sourceFile); + } + } + + return $buffer . $this->footer(); + } + + /** + * Visualizes the result array of + * PHPUnit2_Framework_TestResult::getCodeCoverageInformation() + * and writes it to a file. + * + * @param string $filename + * @access public + * @since Method available since Release 2.2.0 + */ + public function renderToFile($filename) { + if ($fp = fopen($filename, 'w')) { + fputs( + $fp, + $this->render() + ); + + fclose($fp); + } + } + + /** + * Returns summarized Code Coverage data. + * + * Format of the result array: + * + * + * array( + * "/tested/code.php" => array( + * linenumber => flag + * ) + * ) + * + * + * flag > 0: line was executed. + * flag < 0: line is executable but was not executed. + * + * @return array + * @access protected + * @since Method available since Release 2.2.0 + */ + protected function getSummary() { + $summary = array(); + + foreach ($this->codeCoverageInformation as $testCaseName => $sourceFiles) { + foreach ($sourceFiles as $sourceFile => $executedLines) { + foreach ($executedLines as $lineNumber => $flag) { + if (!isset($summary[$sourceFile][$lineNumber])) { + $summary[$sourceFile][$lineNumber] = $flag; + } + + else if ($flag > 0) { + $summary[$sourceFile][$lineNumber] = $flag; + } + } + } + } + + return $summary; + } + + /** + * @return string + * @access protected + * @since Method available since Release 2.1.1 + */ + protected function header() { + } + + /** + * @return string + * @access protected + * @since Method available since Release 2.1.1 + */ + protected function footer() { + } + + /** + * @param string $sourceFile + * @return string + * @access protected + */ + protected function startSourceFile($sourceFile) { + } + + /** + * @param string $sourceFile + * @return string + * @access protected + */ + protected function endSourceFile($sourceFile) { + } + + /** + * @param array $codeLines + * @param array $executedLines + * @return string + * @access protected + * @abstract + */ + abstract protected function renderSourceFile($codeLines, $executedLines); +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Util/CodeCoverage/Renderer/HTML.php b/buildscripts/PHPUnit2/Util/CodeCoverage/Renderer/HTML.php new file mode 100644 index 00000000..66fc4d13 --- /dev/null +++ b/buildscripts/PHPUnit2/Util/CodeCoverage/Renderer/HTML.php @@ -0,0 +1,191 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: HTML.php,v 1.7.2.3 2005/12/17 16:04:58 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.3.0 + */ + +require_once 'PHPUnit2/Util/CodeCoverage/Renderer.php'; + +/** + * Renders Code Coverage information in HTML format. + * + * Formatting of the generated HTML can be achieved through + * CSS (codecoverage.css). + * + * Example + * + * + * td.ccLineNumber, td.ccCoveredLine, td.ccUncoveredLine, td.ccNotExecutableLine { + * font-family: monospace; + * white-space: pre; + * } + * + * td.ccLineNumber, td.ccCoveredLine { + * background-color: #aaaaaa; + * } + * + * td.ccNotExecutableLine { + * color: #aaaaaa; + * } + * + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.1.0 + */ +class PHPUnit2_Util_CodeCoverage_Renderer_HTML extends PHPUnit2_Util_CodeCoverage_Renderer { + const pageHeader = +' + + + + + + +'; + + const pageFooter = +' + +'; + + const sourceFileHeader = +' +'; + + const sourceFileFooter = +'
+'; + + const codeLine = +' %s%s +'; + + /** + * @return string + * @access protected + * @since Method available since Release 2.1.1 + */ + protected function header() { + return self::pageHeader; + } + + /** + * @return string + * @access protected + * @since Method available since Release 2.1.1 + */ + protected function footer() { + return self::pageFooter; + } + + /** + * @param string $sourceFile + * @return string + * @access protected + */ + protected function startSourceFile($sourceFile) { + return self::sourceFileHeader; + } + + /** + * @param string $sourceFile + * @return string + * @access protected + */ + protected function endSourceFile($sourceFile) { + return self::sourceFileFooter; + } + + /** + * @param array $codeLines + * @param array $executedLines + * @return string + * @access protected + */ + protected function renderSourceFile($codeLines, $executedLines) { + $buffer = ''; + $line = 1; + + foreach ($codeLines as $codeLine) { + $lineStyle = 'ccNotExecutableLine'; + + if (isset($executedLines[$line])) { + if ($executedLines[$line] > 0) { + $lineStyle = 'ccCoveredLine'; + } else { + $lineStyle = 'ccUncoveredLine'; + } + } + + $buffer .= sprintf( + self::codeLine, + + $line, + $lineStyle, + htmlspecialchars(rtrim($codeLine)) + ); + + $line++; + } + + return $buffer; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Util/CodeCoverage/Renderer/Text.php b/buildscripts/PHPUnit2/Util/CodeCoverage/Renderer/Text.php new file mode 100644 index 00000000..6b083692 --- /dev/null +++ b/buildscripts/PHPUnit2/Util/CodeCoverage/Renderer/Text.php @@ -0,0 +1,125 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: Text.php,v 1.6.2.3 2005/12/17 16:04:58 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.3.0 + */ + +require_once 'PHPUnit2/Util/CodeCoverage/Renderer.php'; + +/** + * Renders Code Coverage information in text format. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.1.0 + */ +class PHPUnit2_Util_CodeCoverage_Renderer_Text extends PHPUnit2_Util_CodeCoverage_Renderer { + /** + * @param string $sourceFile + * @return string + * @access protected + */ + protected function startSourceFile($sourceFile) { + return ' ' . $sourceFile . "\n\n"; + } + + /** + * @param string $sourceFile + * @return string + * @access protected + */ + protected function endSourceFile($sourceFile) { + return "\n"; + } + + /** + * @param array $codeLines + * @param array $executedLines + * @return string + * @access protected + */ + protected function renderSourceFile($codeLines, $executedLines) { + $buffer = ''; + $line = 1; + + foreach ($codeLines as $codeLine) { + $flag = '-'; + + if (isset($executedLines[$line])) { + if ($executedLines[$line] > 0) { + $flag = '+'; + } else { + $flag = '#'; + } + } + + $buffer .= sprintf( + ' %4u|%s| %s', + + $line, + $flag, + $codeLine + ); + + $line++; + } + + return $buffer; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Util/ErrorHandler.php b/buildscripts/PHPUnit2/Util/ErrorHandler.php new file mode 100644 index 00000000..ee724ffe --- /dev/null +++ b/buildscripts/PHPUnit2/Util/ErrorHandler.php @@ -0,0 +1,77 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: ErrorHandler.php,v 1.1.2.2 2005/12/17 16:04:58 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.3.0 + */ + +/** + * @param integer $errno + * @param string $errstr + * @param string $errfile + * @param integer $errline + * @throws PHPUnit2_Framework_Error + * @since Function available since Release 2.3.0 + */ +function PHPUnit2_Util_ErrorHandler($errno, $errstr, $errfile, $errline) { + $trace = debug_backtrace(); + array_shift($trace); + + throw new PHPUnit2_Framework_Error( + $errstr, + $errno, + $errfile, + $errline, + $trace + ); +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Util/Fileloader.php b/buildscripts/PHPUnit2/Util/Fileloader.php new file mode 100644 index 00000000..bdcd49ed --- /dev/null +++ b/buildscripts/PHPUnit2/Util/Fileloader.php @@ -0,0 +1,109 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: Fileloader.php,v 1.1.2.6 2005/12/19 05:43:56 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.3.0 + */ + +/** + * + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.3.0 + */ +class PHPUnit2_Util_Fileloader { + /** + * Checks if a PHP sourcefile is readable and contains no syntax errors. + * If that is the case, the sourcefile is loaded through include_once(). + * + * @param string $filename + * @throws Exception + * @access public + * @static + */ + public static function checkAndLoad($filename) { + if (!is_readable($filename)) { + $filename = './' . $filename; + } + + if (!is_readable($filename)) { + throw new Exception( + sprintf( + '%s could not be found or is not readable.', + + str_replace('./', '', $filename) + ) + ); + } + + $output = shell_exec('php -l ' . escapeshellarg($filename)); + + if (strpos($output, 'No syntax errors detected in') === FALSE) { + throw new Exception( + sprintf( + 'Syntax error in %s.', + + str_replace('./', '', $filename) + ) + ); + } + + include_once $filename; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Util/Filter.php b/buildscripts/PHPUnit2/Util/Filter.php new file mode 100644 index 00000000..70d055fd --- /dev/null +++ b/buildscripts/PHPUnit2/Util/Filter.php @@ -0,0 +1,263 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: Filter.php,v 1.32.2.5 2005/12/17 16:04:58 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +/** + * Utility class for code filtering. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + */ +class PHPUnit2_Util_Filter { + /** + * Source files that are to be filtered. + * + * @var array + * @access protected + * @static + */ + protected static $filteredFiles = array( + 'PHPUnit2/Extensions/ExceptionTestCase.php', + 'PHPUnit2/Extensions/PerformanceTestCase.php', + 'PHPUnit2/Extensions/RepeatedTest.php', + 'PHPUnit2/Extensions/TestDecorator.php', + 'PHPUnit2/Extensions/TestSetup.php', + 'PHPUnit2/Framework/Assert.php', + 'PHPUnit2/Framework/AssertionFailedError.php', + 'PHPUnit2/Framework/ComparisonFailure.php', + 'PHPUnit2/Framework/Error.php', + 'PHPUnit2/Framework/IncompleteTest.php', + 'PHPUnit2/Framework/IncompleteTestError.php', + 'PHPUnit2/Framework/Test.php', + 'PHPUnit2/Framework/TestCase.php', + 'PHPUnit2/Framework/TestFailure.php', + 'PHPUnit2/Framework/TestListener.php', + 'PHPUnit2/Framework/TestResult.php', + 'PHPUnit2/Framework/TestSuite.php', + 'PHPUnit2/Framework/Warning.php', + 'PHPUnit2/Runner/BaseTestRunner.php', + 'PHPUnit2/Runner/IncludePathTestCollector.php', + 'PHPUnit2/Runner/StandardTestSuiteLoader.php', + 'PHPUnit2/Runner/TestCollector.php', + 'PHPUnit2/Runner/TestSuiteLoader.php', + 'PHPUnit2/Runner/Version.php', + 'PHPUnit2/TextUI/ResultPrinter.php', + 'PHPUnit2/TextUI/TestRunner.php', + 'PHPUnit2/Util/CodeCoverage/Renderer/HTML.php', + 'PHPUnit2/Util/CodeCoverage/Renderer/Text.php', + 'PHPUnit2/Util/CodeCoverage/Renderer.php', + 'PHPUnit2/Util/Log/PEAR.php', + 'PHPUnit2/Util/Log/XML.php', + 'PHPUnit2/Util/TestDox/ResultPrinter/HTML.php', + 'PHPUnit2/Util/TestDox/ResultPrinter/Text.php', + 'PHPUnit2/Util/TestDox/NamePrettifier.php', + 'PHPUnit2/Util/TestDox/ResultPrinter.php', + 'PHPUnit2/Util/ErrorHandler.php', + 'PHPUnit2/Util/Fileloader.php', + 'PHPUnit2/Util/Filter.php', + 'PHPUnit2/Util/Printer.php', + 'PHPUnit2/Util/Skeleton.php', + 'Benchmark/Timer.php', + 'Console/Getopt.php', + 'Log/composite.php', + 'Log/console.php', + 'Log/display.php', + 'Log/error.php', + 'Log/file.php', + 'Log/mail.php', + 'Log/mcal.php', + 'Log/null.php', + 'Log/observer.php', + 'Log/sql.php', + 'Log/sqlite.php', + 'Log/syslog.php', + 'Log/win.php', + 'Log.php', + 'PEAR/Config.php', + 'PEAR.php' + ); + + /** + * Adds a new file to be filtered. + * + * @param string + * @access public + * @static + * @since Method available since Release 2.1.0 + */ + public static function addFileToFilter($filename) { + $filename = self::getCanonicalFilename($filename); + + if (!self::isFiltered($filename)) { + self::$filteredFiles[] = $filename; + } + } + + /** + * Removes a file from the filter. + * + * @param string + * @access public + * @static + * @since Method available since Release 2.1.0 + */ + public static function removeFileFromFilter($filename) { + $filename = self::getCanonicalFilename($filename); + $keys = array_keys(self::$filteredFiles); + + for ($i = 0; $i < sizeof($keys); $i++) { + if (self::$filteredFiles[$keys[$i]] == $filename) { + unset(self::$filteredFiles[$keys[$i]]); + break; + } + } + } + + /** + * Filters source lines from PHPUnit classes. + * + * @param array + * @return array + * @access public + * @static + */ + public static function getFilteredCodeCoverage($codeCoverageInformation) { + $files = array_keys($codeCoverageInformation); + + foreach ($files as $file) { + if (self::isFiltered($file)) { + unset($codeCoverageInformation[$file]); + } + } + + return $codeCoverageInformation; + } + + /** + * Filters stack frames from PHPUnit classes. + * + * @param Exception $e + * @return string + * @access public + * @static + */ + public static function getFilteredStacktrace(Exception $e) { + $filteredStacktrace = ''; + $stacktrace = $e->getTrace(); + + foreach ($stacktrace as $frame) { + $filtered = FALSE; + + if (isset($frame['file']) && !self::isFiltered($frame['file'])) { + $filteredStacktrace .= sprintf( + "%s:%s\n", + + $frame['file'], + isset($frame['line']) ? $frame['line'] : '?' + ); + } + } + + return $filteredStacktrace; + } + + /** + * Canonicalizes a source file name. + * + * @param string $filename + * @return string + * @access protected + * @static + */ + protected static function getCanonicalFilename($filename) { + foreach (array('PHPUnit2', 'Benchmark', 'Console', 'PEAR') as $package) { + $pos = strpos($filename, $package); + + if ($pos !== FALSE) { + $filename = substr($filename, $pos); + break; + } + } + + return str_replace( + '\\', + '/', + $filename + ); + } + + /** + * @param string $filename + * @return boolean + * @access protected + * @static + * @since Method available since Release 2.1.3 + */ + protected static function isFiltered($filename) { + if (substr($filename, -7) == 'phpunit' || + in_array(self::getCanonicalFilename($filename), self::$filteredFiles)) { + return TRUE; + } + + return FALSE; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Util/Log/PEAR.php b/buildscripts/PHPUnit2/Util/Log/PEAR.php new file mode 100644 index 00000000..368c4f54 --- /dev/null +++ b/buildscripts/PHPUnit2/Util/Log/PEAR.php @@ -0,0 +1,220 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: PEAR.php,v 1.2.2.3 2005/12/17 16:04:58 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.3.0 + */ + +require_once 'PHPUnit2/Framework/TestListener.php'; + +@include_once 'Log.php'; + +/** + * A TestListener that logs to a PEAR_Log sink. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.1.0 + */ +class PHPUnit2_Util_Log_PEAR implements PHPUnit2_Framework_TestListener { + /** + * Log. + * + * @var Log + * @access private + */ + private $log; + + /** + * @param string $type The type of concrete Log subclass to use. + * Currently, valid values are 'console', + * 'syslog', 'sql', 'file', and 'mcal'. + * @param string $name The name of the actually log file, table, or + * other specific store to use. Defaults to an + * empty string, with which the subclass will + * attempt to do something intelligent. + * @param string $ident The identity reported to the log system. + * @param array $conf A hash containing any additional configuration + * information that a subclass might need. + * @param int $maxLevel Maximum priority level at which to log. + * @access public + */ + public function __construct($type, $name = '', $ident = '', $conf = array(), $maxLevel = PEAR_LOG_DEBUG) { + $this->log = Log::factory($type, $name, $ident, $conf, $maxLevel); + } + + /** + * An error occurred. + * + * @param PHPUnit2_Framework_Test $test + * @param Exception $e + * @access public + */ + public function addError(PHPUnit2_Framework_Test $test, Exception $e) { + $this->log->crit( + sprintf( + 'Test "%s" failed: %s', + + $test->getName(), + $e->getMessage() + ) + ); + } + + /** + * A failure occurred. + * + * @param PHPUnit2_Framework_Test $test + * @param PHPUnit2_Framework_AssertionFailedError $e + * @access public + */ + public function addFailure(PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $e) { + $this->log->err( + sprintf( + 'Test "%s" failed: %s', + + $test->getName(), + $e->getMessage() + ) + ); + } + + /** + * Incomplete test. + * + * @param PHPUnit2_Framework_Test $test + * @param Exception $e + * @access public + */ + public function addIncompleteTest(PHPUnit2_Framework_Test $test, Exception $e) { + $this->log->info( + sprintf( + 'Test "%s" incomplete: %s', + + $test->getName(), + $e->getMessage() + ) + ); + } + + /** + * A test suite started. + * + * @param PHPUnit2_Framework_TestSuite $suite + * @access public + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit2_Framework_TestSuite $suite) { + $this->log->info( + sprintf( + 'TestSuite "%s" started.', + + $suite->getName() + ) + ); + } + + /** + * A test suite ended. + * + * @param PHPUnit2_Framework_TestSuite $suite + * @access public + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit2_Framework_TestSuite $suite) { + $this->log->info( + sprintf( + 'TestSuite "%s" ended.', + + $suite->getName() + ) + ); + } + + /** + * A test started. + * + * @param PHPUnit2_Framework_Test $test + * @access public + */ + public function startTest(PHPUnit2_Framework_Test $test) { + $this->log->info( + sprintf( + 'Test "%s" started.', + + $test->getName() + ) + ); + } + + /** + * A test ended. + * + * @param PHPUnit2_Framework_Test $test + * @access public + */ + public function endTest(PHPUnit2_Framework_Test $test) { + $this->log->info( + sprintf( + 'Test "%s" ended.', + + $test->getName() + ) + ); + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Util/Log/XML.php b/buildscripts/PHPUnit2/Util/Log/XML.php new file mode 100644 index 00000000..ce528753 --- /dev/null +++ b/buildscripts/PHPUnit2/Util/Log/XML.php @@ -0,0 +1,356 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: XML.php,v 1.2.2.3 2005/12/17 16:04:58 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.3.0 + */ + +require_once 'PHPUnit2/Framework/TestListener.php'; +require_once 'PHPUnit2/Util/Filter.php'; +require_once 'PHPUnit2/Util/Printer.php'; + +require_once 'Benchmark/Timer.php'; + +/** + * A TestListener that generates an XML-based logfile + * of the test execution. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.1.0 + */ +class PHPUnit2_Util_Log_XML extends PHPUnit2_Util_Printer implements PHPUnit2_Framework_TestListener { + /** + * @var DOMDocument + * @access private + */ + private $document; + + /** + * @var DOMElement + * @access private + */ + private $root; + + /** + * @var boolean + * @access private + */ + private $writeDocument = TRUE; + + /** + * @var DOMElement[] + * @access private + */ + private $testSuites = array(); + + /** + * @var integer[] + * @access private + */ + private $testSuiteTests = array(0); + + /** + * @var integer[] + * @access private + */ + private $testSuiteErrors = array(0); + + /** + * @var integer[] + * @access private + */ + private $testSuiteFailures = array(0); + + /** + * @var integer[] + * @access private + */ + private $testSuiteTimes = array(0); + + /** + * @var integer + * @access private + */ + private $testSuiteLevel = 0; + + /** + * @var DOMElement + * @access private + */ + private $currentTestCase = NULL; + + /** + * @var Benchmark_Timer + * @access private + */ + private $timer; + + /** + * Constructor. + * + * @param mixed $out + * @access public + */ + public function __construct($out = NULL) { + $this->document = new DOMDocument('1.0', 'UTF-8'); + $this->document->formatOutput = TRUE; + + $this->root = $this->document->createElement('testsuites'); + $this->document->appendChild($this->root); + + $this->timer = new Benchmark_Timer; + + parent::__construct($out); + } + + /** + * Destructor. + * + * @access public + */ + public function __destruct() { + if ($this->writeDocument === TRUE) { + $this->write($this->getXML()); + } + + parent::__destruct(); + } + + /** + * An error occurred. + * + * @param PHPUnit2_Framework_Test $test + * @param Exception $e + * @access public + */ + public function addError(PHPUnit2_Framework_Test $test, Exception $e) { + $error = $this->document->createElement('error', PHPUnit2_Util_Filter::getFilteredStacktrace($e)); + $error->setAttribute('message', $e->getMessage()); + $error->setAttribute('type', get_class($e)); + + $this->currentTestCase->appendChild($error); + + $this->testSuiteErrors[$this->testSuiteLevel]++; + } + + /** + * A failure occurred. + * + * @param PHPUnit2_Framework_Test $test + * @param PHPUnit2_Framework_AssertionFailedError $e + * @access public + */ + public function addFailure(PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $e) { + $failure = $this->document->createElement('failure', PHPUnit2_Util_Filter::getFilteredStacktrace($e)); + $failure->setAttribute('message', $e->getMessage()); + $failure->setAttribute('type', get_class($e)); + + $this->currentTestCase->appendChild($failure); + + $this->testSuiteFailures[$this->testSuiteLevel]++; + } + + /** + * Incomplete test. + * + * @param PHPUnit2_Framework_Test $test + * @param Exception $e + * @access public + */ + public function addIncompleteTest(PHPUnit2_Framework_Test $test, Exception $e) { + $error = $this->document->createElement('error', PHPUnit2_Util_Filter::getFilteredStacktrace($e)); + $error->setAttribute('message', 'Incomplete Test'); + $error->setAttribute('type', get_class($e)); + + $this->currentTestCase->appendChild($error); + + $this->testSuiteErrors[$this->testSuiteLevel]++; + } + + /** + * A testsuite started. + * + * @param PHPUnit2_Framework_TestSuite $suite + * @access public + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit2_Framework_TestSuite $suite) { + $testSuite = $this->document->createElement('testsuite'); + $testSuite->setAttribute('name', $suite->getName()); + + try { + $class = new ReflectionClass($suite->getName()); + $docComment = $class->getDocComment(); + + if (preg_match('/@category[\s]+([\.\w]+)/', $docComment, $matches)) { + $testSuite->setAttribute('category', $matches[1]); + } + + if (preg_match('/@package[\s]+([\.\w]+)/', $docComment, $matches)) { + $testSuite->setAttribute('package', $matches[1]); + } + + if (preg_match('/@subpackage[\s]+([\.\w]+)/', $docComment, $matches)) { + $testSuite->setAttribute('subpackage', $matches[1]); + } + } + + catch (ReflectionException $e) { + } + + if ($this->testSuiteLevel > 0) { + $this->testSuites[$this->testSuiteLevel]->appendChild($testSuite); + } else { + $this->root->appendChild($testSuite); + } + + $this->testSuiteLevel++; + $this->testSuites[$this->testSuiteLevel] = $testSuite; + $this->testSuiteTests[$this->testSuiteLevel] = 0; + $this->testSuiteErrors[$this->testSuiteLevel] = 0; + $this->testSuiteFailures[$this->testSuiteLevel] = 0; + $this->testSuiteTimes[$this->testSuiteLevel] = 0; + } + + /** + * A testsuite ended. + * + * @param PHPUnit2_Framework_TestSuite $suite + * @access public + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit2_Framework_TestSuite $suite) { + $this->testSuites[$this->testSuiteLevel]->setAttribute('tests', $this->testSuiteTests[$this->testSuiteLevel]); + $this->testSuites[$this->testSuiteLevel]->setAttribute('failures', $this->testSuiteFailures[$this->testSuiteLevel]); + $this->testSuites[$this->testSuiteLevel]->setAttribute('errors', $this->testSuiteErrors[$this->testSuiteLevel]); + $this->testSuites[$this->testSuiteLevel]->setAttribute('time', $this->testSuiteTimes[$this->testSuiteLevel]); + + if ($this->testSuiteLevel > 1) { + $this->testSuiteTests[$this->testSuiteLevel - 1] += $this->testSuiteTests[$this->testSuiteLevel]; + $this->testSuiteErrors[$this->testSuiteLevel - 1] += $this->testSuiteErrors[$this->testSuiteLevel]; + $this->testSuiteFailures[$this->testSuiteLevel - 1] += $this->testSuiteFailures[$this->testSuiteLevel]; + $this->testSuiteTimes[$this->testSuiteLevel - 1] += $this->testSuiteTimes[$this->testSuiteLevel]; + } + + $this->testSuiteLevel--; + } + + /** + * A test started. + * + * @param PHPUnit2_Framework_Test $test + * @access public + */ + public function startTest(PHPUnit2_Framework_Test $test) { + $testCase = $this->document->createElement('testcase'); + $testCase->setAttribute('name', $test->getName()); + $testCase->setAttribute('class', get_class($test)); + + $this->testSuites[$this->testSuiteLevel]->appendChild($testCase); + $this->currentTestCase = $testCase; + + $this->testSuiteTests[$this->testSuiteLevel]++; + + $this->timer->start(); + } + + /** + * A test ended. + * + * @param PHPUnit2_Framework_Test $test + * @access public + */ + public function endTest(PHPUnit2_Framework_Test $test) { + $this->timer->stop(); + $time = $this->timer->timeElapsed(); + + $this->currentTestCase->setAttribute('time', $time); + $this->testSuiteTimes[$this->testSuiteLevel] += $time; + + $this->currentTestCase = NULL; + } + + /** + * Returns the XML as a string. + * + * @return string + * @access public + * @since Method available since Release 2.2.0 + */ + public function getXML() { + return $this->document->saveXML(); + } + + /** + * Enables or disables the writing of the document + * in __destruct(). + * + * This is a "hack" needed for the integration of + * PHPUnit with Phing. + * + * @return string + * @access public + * @since Method available since Release 2.2.0 + */ + public function setWriteDocument($flag) { + if (is_bool($flag)) { + $this->writeDocument = $flag; + } + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Util/Printer.php b/buildscripts/PHPUnit2/Util/Printer.php new file mode 100644 index 00000000..13dc46a9 --- /dev/null +++ b/buildscripts/PHPUnit2/Util/Printer.php @@ -0,0 +1,116 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: Printer.php,v 1.10.2.3 2005/12/17 16:04:58 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.0.0 + */ + +/** + * Utility class that can print to STDOUT or write to a file. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.0.0 + * @abstract + */ +abstract class PHPUnit2_Util_Printer { + /** + * @var resource + * @access private + */ + private $out = NULL; + + /** + * Constructor. + * + * @param mixed $out + * @access public + */ + public function __construct($out = NULL) { + if ($out !== NULL) { + if (is_string($out)) { + $this->out = fopen($out, 'w'); + } else { + $this->out = $out; + } + } + } + + /** + * Destructor. + * + * @access public + */ + public function __destruct() { + if ($this->out !== NULL) { + fclose($this->out); + } + } + + /** + * @param string $buffer + * @access public + */ + public function write($buffer) { + if ($this->out !== NULL) { + fputs($this->out, $buffer); + } else { + print $buffer; + } + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Util/Skeleton.php b/buildscripts/PHPUnit2/Util/Skeleton.php new file mode 100644 index 00000000..39717557 --- /dev/null +++ b/buildscripts/PHPUnit2/Util/Skeleton.php @@ -0,0 +1,340 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: Skeleton.php,v 1.24.2.3 2005/12/17 16:04:58 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.1.0 + */ + +/** + * Class for creating a PHPUnit2_Framework_TestCase skeleton file. + * + * This class will take a classname as a parameter on construction and will + * create a PHP file that contains the skeleton of a PHPUnit2_Framework_TestCase + * subclass. + * + * + * write(); + * ?> + * + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.1.0 + */ +class PHPUnit2_Util_Skeleton { + protected $templateClassHeader = +' +'; + + protected $templateMethod = +' + /** + * @todo Implement test{methodName}(). + */ + public function test{methodName}() { + // Remove the following line when you implement this test. + throw new PHPUnit2_Framework_IncompleteTestError; + } +'; + + /** + * @var string + * @access protected + */ + protected $className; + + /** + * @var string + * @access protected + */ + protected $classSourceFile; + + /** + * Constructor. + * + * @param string $className + * @param string $classSourceFile + * @throws Exception + * @access public + */ + public function __construct($className, $classSourceFile = '') { + if ($classSourceFile == '') { + $classSourceFile = $className . '.php'; + } + + if (file_exists($classSourceFile)) { + $this->classSourceFile = $classSourceFile; + } else { + throw new Exception( + sprintf( + 'Could not open %s.', + + $classSourceFile + ) + ); + } + + @include_once $this->classSourceFile; + + if (class_exists($className)) { + $this->className = $className; + } else { + throw new Exception( + sprintf( + 'Could not find class "%s" in %s.', + + $className, + $classSourceFile + ) + ); + } + } + + /** + * Generates the test class' source. + * + * @return string + * @access public + */ + public function generate() { + $testClassSource = $this->testClassHeader($this->className, $this->classSourceFile); + + $class = new ReflectionClass($this->className); + + foreach ($class->getMethods() as $method) { + if (!$method->isConstructor() && + !$method->isAbstract() && + $method->isUserDefined() && + $method->isPublic() && + $method->getDeclaringClass()->getName() == $this->className) { + $testClassSource .= $this->testMethod($method->getName()); + } + } + + $testClassSource .= $this->testClassFooter($this->className); + + return $testClassSource; + } + + /** + * Generates the test class and writes it to a source file. + * + * @param string $file + * @access public + */ + public function write($file = '') { + if ($file == '') { + $file = $this->className . 'Test.php'; + } + + if ($fp = @fopen($file, 'w')) { + @fputs($fp, $this->generate()); + @fclose($fp); + } + } + + /** + * Sets the templates for class header, class footer, and method. + * + * @param string $classHeader + * @param string $classFooter + * @param string $method + * @access public + * @since Method available since Release 2.2.0 + */ + public function setTemplates($classHeader, $classFooter, $method) { + if (is_file($classHeader)) { + $this->templateClassHeader = file_get_contents($classHeader); + } else { + $this->templateClassHeader = $classHeader; + } + + if (is_file($classFooter)) { + $this->templateClassFooter = file_get_contents($classFooter); + } else { + $this->templateClassFooter = $classFooter; + } + + if (is_file($method)) { + $this->templateMethod = file_get_contents($method); + } else { + $this->templateMethod = $method; + } + } + + /** + * @param string $className + * @param string $classSourceFile + * @access protected + */ + protected function testClassHeader($className, $classSourceFile) { + return str_replace( + array( + '{className}', + '{classFile}', + '{date}', + '{time}' + ), + array( + $className, + $classSourceFile, + date('Y-m-d'), + date('H:i:s') + ), + $this->templateClassHeader + ); + } + + /** + * @param string $className + * @access protected + */ + protected function testClassFooter($className) { + return str_replace( + array( + '{className}' + ), + array( + $className + ), + $this->templateClassFooter + ); + } + + /** + * @param string $methodName + * @access protected + */ + protected function testMethod($methodName) { + return str_replace( + array( + '{methodName}' + ), + array( + ucfirst($methodName) + ), + $this->templateMethod + ); + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Util/TestDox/NamePrettifier.php b/buildscripts/PHPUnit2/Util/TestDox/NamePrettifier.php new file mode 100644 index 00000000..1d686dc8 --- /dev/null +++ b/buildscripts/PHPUnit2/Util/TestDox/NamePrettifier.php @@ -0,0 +1,165 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: NamePrettifier.php,v 1.2.2.2 2005/12/17 16:04:58 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.3.0 + */ + +/** + * Prettifies class and method names for use in TestDox documentation. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.1.0 + */ +class PHPUnit2_Util_TestDox_NamePrettifier { + /** + * @var string + * @access protected + */ + protected $prefix = 'Test'; + + /** + * @var string + * @access protected + */ + protected $suffix = 'Test'; + + /** + * Tests if a method is a test method. + * + * @param string $testMethodName + * @return boolean + * @access public + */ + public function isATestMethod($testMethodName) { + if (substr($testMethodName, 0, 4) == 'test') { + return TRUE; + } + + return FALSE; + } + + /** + * Prettifies the name of a test class. + * + * @param string $testClassName + * @return string + * @access public + */ + public function prettifyTestClass($testClassName) { + $title = $testClassName; + + if ($this->suffix !== NULL && + $this->suffix == substr($testClassName, -1 * strlen($this->suffix))) { + $title = substr($title, 0, strripos($title, $this->suffix)); + } + + if ($this->prefix !== NULL && + $this->prefix == substr($testClassName, 0, strlen($this->prefix))) { + $title = substr($title, strlen($this->prefix)); + } + + return $title; + } + + /** + * Prettifies the name of a test method. + * + * @param string $testMethodName + * @return string + * @access public + */ + public function prettifyTestMethod($testMethodName) { + $buffer = ''; + + $testMethodName = preg_replace('#\d+$#', '', $testMethodName); + + for ($i = 4; $i < strlen($testMethodName); $i++) { + if ($i > 4 && + ord($testMethodName[$i]) >= 65 && + ord($testMethodName[$i]) <= 90) { + $buffer .= ' ' . strtolower($testMethodName[$i]); + } else { + $buffer .= $testMethodName[$i]; + } + } + + return $buffer; + } + + /** + * Sets the prefix of test names. + * + * @param string $prefix + * @access public + */ + public function setPrefix($prefix) { + $this->prefix = $prefix; + } + + /** + * Sets the suffix of test names. + * + * @param string $prefix + * @access public + */ + public function setSuffix($suffix) { + $this->suffix = $suffix; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Util/TestDox/ResultPrinter.php b/buildscripts/PHPUnit2/Util/TestDox/ResultPrinter.php new file mode 100644 index 00000000..274c7309 --- /dev/null +++ b/buildscripts/PHPUnit2/Util/TestDox/ResultPrinter.php @@ -0,0 +1,299 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: ResultPrinter.php,v 1.2.2.6 2005/12/17 16:04:58 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.3.0 + */ + +require_once 'PHPUnit2/Framework/TestListener.php'; +require_once 'PHPUnit2/Util/TestDox/NamePrettifier.php'; +require_once 'PHPUnit2/Util/Printer.php'; + +/** + * Base class for printers of TestDox documentation. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.1.0 + * @abstract + */ +abstract class PHPUnit2_Util_TestDox_ResultPrinter extends PHPUnit2_Util_Printer implements PHPUnit2_Framework_TestListener { + /** + * @var PHPUnit2_Util_TestDox_NamePrettifier + * @access protected + */ + protected $prettifier; + + /** + * @var string + * @access protected + */ + protected $testClass = ''; + + /** + * @var boolean + * @access protected + */ + protected $testFailed = FALSE; + + /** + * @var array + * @access protected + */ + protected $tests = array(); + + /** + * Constructor. + * + * @param resource $out + * @access public + */ + public function __construct($out = NULL) { + parent::__construct($out); + + $this->prettifier = new PHPUnit2_Util_TestDox_NamePrettifier; + $this->startRun(); + } + + /** + * Destructor. + * + * @access public + */ + public function __destruct() { + $this->doEndClass(); + $this->endRun(); + + parent::__destruct(); + } + + /** + * Abstract Factory. + * + * @param string $type + * @param resource $out + * @throws Exception + * @access public + * @static + */ + public static function factory($type, $out = NULL) { + require_once 'PHPUnit2/Util/TestDox/ResultPrinter/' . $type . '.php'; + + $class = 'PHPUnit2_Util_TestDox_ResultPrinter_' . $type; + return new $class($out); + } + + /** + * An error occurred. + * + * @param PHPUnit2_Framework_Test $test + * @param Exception $e + * @access public + */ + public function addError(PHPUnit2_Framework_Test $test, Exception $e) { + $this->testFailed = TRUE; + } + + /** + * A failure occurred. + * + * @param PHPUnit2_Framework_Test $test + * @param PHPUnit2_Framework_AssertionFailedError $e + * @access public + */ + public function addFailure(PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $e) { + $this->testFailed = TRUE; + } + + /** + * Incomplete test. + * + * @param PHPUnit2_Framework_Test $test + * @param Exception $e + * @access public + */ + public function addIncompleteTest(PHPUnit2_Framework_Test $test, Exception $e) { + $this->testFailed = TRUE; + } + + /** + * A testsuite started. + * + * @param PHPUnit2_Framework_TestSuite $suite + * @access public + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit2_Framework_TestSuite $suite) { + } + + /** + * A testsuite ended. + * + * @param PHPUnit2_Framework_TestSuite $suite + * @access public + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit2_Framework_TestSuite $suite) { + } + + /** + * A test started. + * + * @param PHPUnit2_Framework_Test $test + * @access public + */ + public function startTest(PHPUnit2_Framework_Test $test) { + $class = get_class($test); + + if ($this->testClass != $class) { + if ($this->testClass != '') { + $this->doEndClass(); + } + + $this->startClass($this->prettifier->prettifyTestClass($class)); + + $this->testClass = $class; + $this->tests = array(); + } + + $this->testFailed = FALSE; + } + + /** + * A test ended. + * + * @param PHPUnit2_Framework_Test $test + * @access public + */ + public function endTest(PHPUnit2_Framework_Test $test) { + $prettifiedName = $this->prettifier->prettifyTestMethod($test->getName()); + + if (!isset($this->tests[$prettifiedName])) { + if (!$this->testFailed) { + $this->tests[$prettifiedName]['success'] = 1; + $this->tests[$prettifiedName]['failure'] = 0; + } else { + $this->tests[$prettifiedName]['success'] = 0; + $this->tests[$prettifiedName]['failure'] = 1; + } + } else { + if (!$this->testFailed) { + $this->tests[$prettifiedName]['success']++; + } else { + $this->tests[$prettifiedName]['failure']++; + } + } + } + + /** + * @access private + * @since Method available since Release 2.3.0 + */ + private function doEndClass() { + foreach ($this->tests as $name => $data) { + if ($data['failure'] == 0) { + $this->onTest($name); + } + } + + $this->endClass($this->prettifier->prettifyTestClass($this->testClass)); + } + + /** + * Handler for 'start run' event. + * + * @access protected + */ + protected function startRun() { + } + + /** + * Handler for 'start class' event. + * + * @param string $name + * @access protected + * @abstract + */ + abstract protected function startClass($name); + + /** + * Handler for 'on test' event. + * + * @param string $name + * @access protected + * @abstract + */ + abstract protected function onTest($name); + + /** + * Handler for 'end class' event. + * + * @param string $name + * @access protected + * @abstract + */ + abstract protected function endClass($name); + + /** + * Handler for 'end run' event. + * + * @access protected + */ + protected function endRun() { + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Util/TestDox/ResultPrinter/HTML.php b/buildscripts/PHPUnit2/Util/TestDox/ResultPrinter/HTML.php new file mode 100644 index 00000000..505ec60d --- /dev/null +++ b/buildscripts/PHPUnit2/Util/TestDox/ResultPrinter/HTML.php @@ -0,0 +1,120 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: HTML.php,v 1.2.2.3 2005/12/17 16:04:58 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.3.0 + */ + +require_once 'PHPUnit2/Util/TestDox/ResultPrinter.php'; + +/** + * Prints TestDox documentation in HTML format. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.1.0 + */ +class PHPUnit2_Util_TestDox_ResultPrinter_HTML extends PHPUnit2_Util_TestDox_ResultPrinter { + /** + * Handler for 'start run' event. + * + * @access protected + */ + protected function startRun() { + $this->write(''); + } + + /** + * Handler for 'start class' event. + * + * @param string $name + * @access protected + */ + protected function startClass($name) { + $this->write('

' . $name . '

    '); + } + + /** + * Handler for 'on test' event. + * + * @param string $name + * @access protected + */ + protected function onTest($name) { + $this->write('
  • ' . $name . '
  • '); + } + + /** + * Handler for 'end class' event. + * + * @param string $name + * @access protected + */ + protected function endClass($name) { + $this->write('
'); + } + + /** + * Handler for 'end run' event. + * + * @access protected + */ + protected function endRun() { + $this->write(''); + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/Util/TestDox/ResultPrinter/Text.php b/buildscripts/PHPUnit2/Util/TestDox/ResultPrinter/Text.php new file mode 100644 index 00000000..cd12e525 --- /dev/null +++ b/buildscripts/PHPUnit2/Util/TestDox/ResultPrinter/Text.php @@ -0,0 +1,102 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: Text.php,v 1.2.2.3 2005/12/17 16:04:58 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit2 + * @since File available since Release 2.3.0 + */ + +require_once 'PHPUnit2/Util/TestDox/ResultPrinter.php'; + +/** + * Prints TestDox documentation in text format. + * + * @category Testing + * @package PHPUnit2 + * @author Sebastian Bergmann + * @copyright 2002-2006 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit2 + * @since Class available since Release 2.1.0 + */ +class PHPUnit2_Util_TestDox_ResultPrinter_Text extends PHPUnit2_Util_TestDox_ResultPrinter { + /** + * Handler for 'start class' event. + * + * @param string $name + * @access protected + */ + protected function startClass($name) { + $this->write($name . "\n"); + } + + /** + * Handler for 'on test' event. + * + * @param string $name + * @access protected + */ + protected function onTest($name) { + $this->write(' - ' . $name . "\n"); + } + + /** + * Handler for 'end class' event. + * + * @param string $name + * @access protected + */ + protected function endClass($name) { + $this->write("\n"); + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/buildscripts/PHPUnit2/pear-phpunit b/buildscripts/PHPUnit2/pear-phpunit new file mode 100644 index 00000000..25e8944d --- /dev/null +++ b/buildscripts/PHPUnit2/pear-phpunit @@ -0,0 +1,41 @@ +#!@php_bin@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: pear-phpunit,v 1.2.8.2 2005/12/17 16:04:56 sebastian Exp $ + */ + +require 'PHPUnit2/TextUI/TestRunner.php'; +?> diff --git a/buildscripts/PHPUnit2/pear-phpunit.bat b/buildscripts/PHPUnit2/pear-phpunit.bat new file mode 100644 index 00000000..d7aadb5c --- /dev/null +++ b/buildscripts/PHPUnit2/pear-phpunit.bat @@ -0,0 +1,39 @@ +@echo off +REM PHP Version 5 +REM +REM Copyright (c) 2002-2006, Sebastian Bergmann . +REM All rights reserved. +REM +REM Redistribution and use in source and binary forms, with or without +REM modification, are permitted provided that the following conditions +REM are met: +REM +REM * Redistributions of source code must retain the above copyright +REM notice, this list of conditions and the following disclaimer. +REM +REM * Redistributions in binary form must reproduce the above copyright +REM notice, this list of conditions and the following disclaimer in +REM the documentation and/or other materials provided with the +REM distribution. +REM +REM * Neither the name of Sebastian Bergmann nor the names of his +REM contributors may be used to endorse or promote products derived +REM from this software without specific prior written permission. +REM +REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +REM "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +REM LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +REM FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +REM COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +REM INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +REM BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +REM LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +REM CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC +REM LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +REM ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +REM POSSIBILITY OF SUCH DAMAGE. +REM +REM $Id: pear-phpunit.bat,v 1.3.2.2 2005/12/17 16:04:56 sebastian Exp $ +REM + +"@php_bin@" "@php_dir@/PHPUnit2/TextUI/TestRunner.php" %* diff --git a/buildscripts/PhpDocumentor/PHPLICENSE.txt b/buildscripts/PhpDocumentor/PHPLICENSE.txt new file mode 100644 index 00000000..c88b3873 --- /dev/null +++ b/buildscripts/PhpDocumentor/PHPLICENSE.txt @@ -0,0 +1,69 @@ +-------------------------------------------------------------------- + The PHP License, version 3.0 +Copyright (c) 1999 - 2002 The PHP Group. All rights reserved. +-------------------------------------------------------------------- + +Redistribution and use in source and binary forms, with or without +modification, is permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + 3. The name "PHP" must not be used to endorse or promote products + derived from this software without prior written permission. For + written permission, please contact group@php.net. + + 4. Products derived from this software may not be called "PHP", nor + may "PHP" appear in their name, without prior written permission + from group@php.net. You may indicate that your software works in + conjunction with PHP by saying "Foo for PHP" instead of calling + it "PHP Foo" or "phpfoo" + + 5. The PHP Group may publish revised and/or new versions of the + license from time to time. Each version will be given a + distinguishing version number. + Once covered code has been published under a particular version + of the license, you may always continue to use it under the terms + of that version. You may also choose to use such covered code + under the terms of any subsequent version of the license + published by the PHP Group. No one other than the PHP Group has + the right to modify the terms applicable to covered code created + under this License. + + 6. Redistributions of any form whatsoever must retain the following + acknowledgment: + "This product includes PHP, freely available from + ". + +THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND +ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP +DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------- + +This software consists of voluntary contributions made by many +individuals on behalf of the PHP Group. + +The PHP Group can be contacted via Email at group@php.net. + +For more information on the PHP Group and the PHP project, +please see . + +This product includes the Zend Engine, freely available at +. + diff --git a/buildscripts/PhpDocumentor/new_phpdoc.php b/buildscripts/PhpDocumentor/new_phpdoc.php new file mode 100644 index 00000000..e4adea90 --- /dev/null +++ b/buildscripts/PhpDocumentor/new_phpdoc.php @@ -0,0 +1,662 @@ + + +// Joshua Eichorn +// Gregory Beaver +// +// phpDocumentor, a program for creating javadoc style documentation from php code +// Copyright (C) 2000-2002 Joshua Eichorn +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// +// Copyleft 2001 Juan Pablo Morales + +if (!function_exists('version_compare')) +{ + print "phpDocumentor requires PHP version 4.1.0 or greater to function"; + exit; +} + +// set up include path so we can find all files, no matter what +$GLOBALS['_phpDocumentor_install_dir'] = dirname(realpath(__FILE__)); +// add my directory to the include path, and make it first, should fix any errors +if (substr(PHP_OS, 0, 3) == 'WIN') +ini_set('include_path',$GLOBALS['_phpDocumentor_install_dir'].';'.ini_get('include_path')); +else +ini_set('include_path',$GLOBALS['_phpDocumentor_install_dir'].':'.ini_get('include_path')); + +/** +* common file information +*/ +include_once("phpDocumentor/common.inc.php"); + +// find the .ini directory by parsing phpDocumentor.ini and extracting _phpDocumentor_options[userdir] +$ini = phpDocumentor_parse_ini_file($_phpDocumentor_install_dir . PATH_DELIMITER . 'phpDocumentor.ini', true); +if (isset($ini['_phpDocumentor_options']['userdir'])) + $configdir = $ini['_phpDocumentor_options']['userdir']; +else + $configdir = $_phpDocumentor_install_dir . '/user'; + +// allow the user to change this at runtime +if (!empty($_REQUEST['altuserdir'])) $configdir = $_REQUEST['altuserdir']; +?> + + + + Form to submit to phpDocumentor v<?php print PHPDOCUMENTOR_VER; ?> + + + + path = $path; + $options = array(); + if ($text) $options['text'] = $text; + if ($link) $options['link'] = $link; + if ($icon) $options['icon'] = $icon; + HTML_TreeNode::HTML_TreeNode($options,$events); + } + } + + function getDir($path,&$node) + { + global $pd; + if (!$dir = opendir($path)) return; + + $node = new HTML_TreeNode(array('text' => basename(realpath($path)), 'link' => "", 'icon' => 'folder.gif')); + while (($file = readdir($dir)) !== false) + { + if ($file != '.' && $file != '..') + { + if (is_dir("$path$pd$file") && !is_link("$path$pd$file")) + { + $entry[] = "$path$pd$file"; + } + } + } + closedir($dir); + for($i = 0; $i < count($entry); $i++) + { + $node->addItem(new HTML_TreeNode(array('text'=>basename(realpath($entry[$i])), 'link' => "javascript:setHelp('".addslashes(realpath($entry[$i]))."');", 'icon' => 'folder.gif'))); + } + } + + function recurseDir($path, &$node) { + global $pd; + if (!$dir = opendir($path)) { + return false; + } + $anode = new HTML_TreeNode(array('text' => basename($path), 'link' => "javascript:setHelpVal('".$path."');", 'icon' => 'folder.gif')); + $result = addslashes(realpath(stripslashes($path).$pd."..")); + if (!$node) $anode->addItem(new DirNode('..',"javascript:setHelp('".$result."');",'folder.gif'),'..'); + while (($file = readdir($dir)) !== false) { + if ($file != '.' && $file != '..') { + if (is_dir("$path$pd$file")) { + recurseDir("$path$pd$file",$anode); + } + } + } + rewinddir($dir);// + while (false){//($file = readdir($dir)) !== false) { + if ($file != '.' && $file != '..') { + if (is_file("$path$pd$file")) { + $anode->addItem(new DirNode($file,"javascript:setHelpVal('$path$pd$file');",'branchtop.gif',"$path$pd$file")); + } + } + } + if (!$node) $node = $anode; + else + $node->addItem($anode); + closedir($dir); + } + + function switchDirTree($path, &$node) + { + global $pd; + + // initialize recursion simulation values + // array format: path => &parent in $node itemlist + $parent = array(); + $parent_indexes = array(); + $parenti = 1; + + $node = new DirNode(basename($path),"javascript:setHelpVal('".$path."');",'folder.gif',$path); + $result = addslashes(realpath($path.$pd."..")); + $node->addItem(new DirNode('..',"javascript:setHelp('".$result."');",'folder.gif','..')); + $rnode = &$node; + $parent[realpath($path)] = false; + $recur = 0; + do + { + if ($recur++ > 120) return; + if (!$dir = @opendir($path)) { + // no child files or directories +// echo "$path no child files or directories return to "; + $rnode = &$parent[realpath($path)]; + $path = $rnode->path; + if (isset($parent_indexes[realpath($path)])) $parenti = $parent_indexes[realpath($path)]; +// echo "$path parenti $parenti
"; + } +// fancy_debug($path,$parent_indexes); +// vdump_par($parent); + if (!isset($parent_indexes[realpath($path)])) + { + $file = readdir($dir); + while ($file !== false) { + if ($file != '.' && $file != '..') { + if (@is_dir(realpath("$path$pd$file"))) { + if (!isset($parent_indexes[realpath($path)])) $parent_indexes[realpath($path)] = true; + $parent[realpath("$path$pd$file")] = &$rnode; +// echo "
adding new ".addslashes(realpath($path.$pd.$file))." to $path
"; + $rnode->addItem(new DirNode(addslashes(realpath("$path$pd$file")),"javascript:setHelpVal('".addslashes(realpath($path.$pd.$file))."');",'folder.gif',addslashes(realpath($path.$pd.$file)))); + } + } + $file = readdir($dir); + } + } + // go down the tree if possible + if (isset($parent_indexes[realpath($path)])) + { + if ($parenti + 1 > (count($rnode->items))) + { + // no more children, go back up to parent +// echo "$path no more children, go back up to parent "; + $rnode = &$parent[realpath($path)]; + $path = $rnode->path; + if (isset($parent_indexes[realpath($path)])) $parenti = $parent_indexes[realpath($path)]; +// echo $path." parenti $parenti
"; + } else + { + // go to next child +// echo "$path go to next child "; + $parent_indexes[realpath($path)] = $parenti+1; +// debug("set parent ".$rnode->items[$parenti]->path." = ".$rnode->path.'
'); + $parent[realpath($rnode->items[$parenti]->path)] = &$rnode; + $rnode = &$rnode->items[$parenti]; + $path = $rnode->path; +// echo "$path
"; + $parenti = 0; + } + } else + { + // no children, go back up the tree to the next child +// echo "$path no children, go back up to parent "; + $rnode = &$parent[realpath($path)]; + $path = $rnode->path; + if (isset($parent_indexes[realpath($path)])) $parenti = $parent_indexes[realpath($path)]; +// echo "$path parenti $parenti
"; + } + @closedir($dir); + } while ($path && (($parenti < (count($rnode->items))) || ($parent[realpath($path)] !== false))); + } + + function vdump_par($tree) + { + foreach($tree as $key => $val) + { + if ($val === false) + debug($key.' -> false
'); + else + debug($key.' -> ' .$val->path.'
'); + } + debug('
'); + } + + $menu = new HTML_TreeMenu(); + $filename = ''; + if (isset($_GET) && isset($_GET['fileName'])) $filename = $_GET['fileName']; + $filename = realpath($filename); + $pd = (substr(PHP_OS, 0, 3) == 'WIN') ? '\\' : '/'; + $test = ($pd == '/') ? '/' : 'C:\\'; + if (empty($filename) || ($filename == $test)) + { + $filename = ($pd == '/') ? '/' : 'C:\\'; + $node = false; + getDir($filename,$node); + } else + { + flush(); +// if ($pd != '/') $pd = $pd.$pd; + $anode = false; + switchDirTree($filename,$anode); +// recurseDir($filename,$anode); + $node = new HTML_TreeNode(array('text' => "Click to view $filename",'link' => "",'icon' => 'branchtop.gif')); + $node->addItem($anode); + }; + $menu->addItem($node); + $DHTMLmenu = &new HTML_TreeMenu_DHTML($menu, array('images' => 'HTML_TreeMenu-1.1.2/images')); + ?> + + + "; + echo "

Parsing Files ...

"; + flush(); + echo "
\n";
+    /** phpdoc.inc */
+    include("phpDocumentor/phpdoc.inc");
+    echo "
\n"; + echo "

Operation Completed!!

"; + } else + { + ?> + +

+ phpDocumentor v Web Interface +

+ phpDocumentor written by Joshua Eichorn
+ Web Interface written by Juan Pablo Morales and enhanced by Greg Beaver
+ + + + + + +
+ Help + + use this to find directories and files which can be used below +
+ + +
+ +printMenu(); +?> +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Use a pre-created config file for form values. + + Normally, phpDocumentor uses the form values from this form to set up parsing. In version 1.2, + phpDocumentor allows you to "save" form values in configuration files so that you can replicate + common complicated documentation tasks with only one time. Just choose a config file below or create a + new one and refresh this page to choose it.
change config directory:changed to "'.$_REQUEST['altuserdir'].'"'; ?> + Choose a config:
+
+ Target + + Target is the directory where + the output produced by phpDocumentor will reside
+
+ + Add the directory in the help box +
+ Files to parse + + This is a group of comma-separated names of php files + or tutorials that will be processed by phpDocumentor.
+
+ + Add the file in the help box +
+ Directory to parse + + This is a group of comma-separated directories where php files + or tutorials are found that will be processed by phpDocumentor. + phpDocumentor automatically parses subdirectories
+
+ + Add the directory in the help box +
+ Files to ignore + + A list of files (full path or filename), and patterns + to ignore. Patterns may use wildcards * and ?. To + ignore all subdirectories named "test" for example, + using "test/" To ignore all files and directories + with test in their name use "*test*" +
+ + Add the directory in the help box +
+ Generated Documentation Title + + Choose a title for the generated documentation
+
+
+ Default Package Name + + Choose a name for the default package
+
+
+ Custom Tags + + Custom Tags is a comma-separated list of tags + you want phpDocumentor to include as valid tags + in this parse. An example would be "value, size" + to allow @value and @size tags. +
+
+ Packages to parse + + The parameter packages is a group of comma + separated names of abstract packages that will + be processed by phpDocumentor. All package names must be + separated by commas.
+
+
+ Output Information + +
+ Outputformat + may be HTML, XML, PDF, or CHM (case-sensitive) in version 1.2. There is only one Converter + for both CHM and PDF, default. There are 2 HTML Converters, + frames and Smarty. frames templates may be any of:

+ default, l0l33t, phpdoc.de, phphtmllib, phpedit, DOM/default, DOM/l0l33t, or DOM/phpdoc.de. + Smarty templates may be any of:

+ default or PHP.
+
+There is only 1 template for all other Converters, default +
Output type:Converter name:template name
+
+ + Add the converter in the help box
+ + Use ONLY the converter in the help box +
+ Parse @access private + + The parameter Parse @access private tells phpDocumentor + whether to parse elements with an "@access private" tag in their docblock
+ Parse private
+
+ JavaDoc-compliant Description parsing. + + Normally, phpDocumentor uses several rules to determine the short description. This switch + asks phpDocumentor to simply search for the first period (.) and use it to delineate the short + description. In addition, the short description will not be separated from the long description
+ JavaDoc-compliant Description
+
+ +
+
+
+
+

+ Joshua Eichorn jeichorn@phpdoc.org
+ Juan Pablo Morales ju-moral@uniandes.edu.co
+ Gregory Beaver cellog@users.sourceforge.net +

+

+ If you have any problems with phpDocumentor, please visit the website: phpdocu.sourceforge.net and + submit a bug +

+ + +
+Last modified: $Date: 2005/10/17 18:15:16 $
+Revision: $Revision: 1.1 $
+
+ + + + + diff --git a/buildscripts/PhpDocumentor/pear-phpdoc b/buildscripts/PhpDocumentor/pear-phpdoc new file mode 100644 index 00000000..258af7c8 --- /dev/null +++ b/buildscripts/PhpDocumentor/pear-phpdoc @@ -0,0 +1,38 @@ +#!@PHP-BIN@ + diff --git a/buildscripts/PhpDocumentor/pear-phpdoc.bat b/buildscripts/PhpDocumentor/pear-phpdoc.bat new file mode 100644 index 00000000..04e3bcc3 --- /dev/null +++ b/buildscripts/PhpDocumentor/pear-phpdoc.bat @@ -0,0 +1,145 @@ +@ECHO OFF +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: +:: Batch file to start phpDocumentor with PHP's CLI +:: +:: This SW was contributed by BlueShoes www.blueshoes.org "The PHP Framework" +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +::---------------------------------------------------------------------------------- +:: Please set following to PHP's CLI +:: NOTE: In PHP 4.2.x the PHP-CLI used to be named php-cli.exe. +:: PHP 4.3.x names it php.exe but stores it in a subdir called /cli/php.exe +:: E.g. for PHP 4.2 C:\phpdev\php-4.2-Win32\php-cli.exe +:: for PHP 4.3 C:\phpdev\php-4.3-Win32\cli\php.exe + + SET phpCli=@PHP-BIN@ + + + +::--------------------------------------------------------------------------------- +::--------------------------------------------------------------------------------- +:: Do not modify below this line!! (Unless you know what your doing :) +::--------------------------------------------------------------------------------- +::--------------------------------------------------------------------------------- + +:: Only show this intro when no options are passed +IF '%1'=='' ( + ECHO ****************************************************************************** + ECHO * PhpDocument Command-Line Starter + ECHO * + ECHO * phpDocumentor is a JavaDoc-like automatic documentation generator for PHP + ECHO * written in PHP. It is the most versatile tool for documenting PHP. + ECHO * + ECHO * This batch-file will try to run the phpDocumentor using the command-line + ECHO * version of PHP4. NOTE: It will not run with the PHP ISAPI module! + ECHO * Please update the path in this batch-file to your PHP-CLI. + ECHO * + ECHO * Tip: o Grab a copy of one of the ini-files in the user/ dir of the + ECHO * phpDocumentor and modify the settings there. + ECHO * o To see the command line options type phpdoc -h + ECHO * + ECHO * @version 1.3 2003-06-28 + ECHO * @author Sam Blum sam@blueshoes.org + ECHO * @Copyright Free Software released under the GNU/GPL license + ECHO * + ECHO * This SW was contributed by BlueShoes www.blueshoes.org "The PHP Framework" + ECHO ****************************************************************************** +) + +:: Check existence of php.exe +IF EXIST "%phpCli%" ( + SET doNothing= +) ELSE GOTO :NoPhpCli + +:: If called using options, just call phpdoc and end after without pausing. +:: This will allow use where pausing is not wanted. +IF '%1'=='' ( + SET doNothing= +) ELSE ( + "%phpCli%" "@BIN-DIR@\phpdoc" %* + GOTO :EOF +) + + +SET iniFile= + +ECHO ------------------------------------------------------------------------------ +ECHO Select Ini-File [default is phpDocumentor.ini] +ECHO ------------------------------------------------------------------------------ +ECHO # 0: phpDocumentor.ini +SET count=0 +FOR /R "@DATA-DIR@\PhpDocumentor\user" %%I IN (*.ini) DO ( + SET /a count+=1 + CALL :exec ECHO # %%count%%: %%~nI%%~xI +) + +:LOOP_1 +:: SET /P prompts for input and sets the variable +:: to whatever the user types +SET iniNr= +SET /P iniNr=Type a number and press Enter[0]: + +:: Use default +IF '%iniNr%'=='' ( + SET iniNr=0 +) + +:: Check for default selection +SET iniFile=phpDocumentor.ini +IF %iniNr%==0 ( + CALL :exec GOTO :run + GOTO :PAUSE_END +) + +:: Check selected +SET count=0 +SET found= +FOR /R "@DATA-DIR@\PhpDocumentor\user" %%I IN (*.ini) DO ( + SET /a count+=1 + SET iniFile=%%~nI%%~xI + CALL :exec IF '%%iniNr%%'=='%%count%%' GOTO :run +) + +:: Check if selected # was found +IF '%found%'=='' ( + ECHO Invalid input [%iniNr%]... try again + ECHO. + GOTO :LOOP_1 +) + +:: +:: php.exe not found error +GOTO :PAUSE_END +:NoPhpCli +ECHO ** ERROR ***************************************************************** +ECHO * Sorry, can't find the php.exe file. +ECHO * You must edit this file to point to your php.exe (CLI version!) +ECHO * [Currently set to %phpCli%] +ECHO * +ECHO * NOTE: In PHP 4.2.x the PHP-CLI used to be named php-cli.exe. +ECHO * PHP 4.3.x renamed it php.exe but stores it in a subdir +ECHO * called /cli/php.exe +ECHO * E.g. for PHP 4.2 C:\phpdev\php-4.2-Win32\php-cli.exe +ECHO * for PHP 4.3 C:\phpdev\php-4.3-Win32\cli\php.exe +ECHO ************************************************************************** + +:: +:: Stupid MS-batch: Can't evaluate environment variable inside a FOR loop!!! :(( +GOTO :PAUSE_END +:exec +%* +GOTO :EOF + +:: +:: Start the phpDocumentor +GOTO :PAUSE_END +:run +SET found=1 +ECHO Starting: "%phpCli%" "@BIN-DIR@\phpdoc" -c "%iniFile%" +ECHO. +"%phpCli%" "@BIN-DIR@\phpdoc" -c "%iniFile%" +GOTO :EOF + +:PAUSE_END +PAUSE \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor.ini b/buildscripts/PhpDocumentor/phpDocumentor.ini new file mode 100644 index 00000000..bbb01631 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor.ini @@ -0,0 +1,118 @@ +;; phpDocumentor.ini +;; +;; contains all the runtime values that are configurable. +;; This is moved from phpdoc.inc, to remove the necessity to edit the php code and +;; simplify debugging +[DEBUG] +;; If you want to see the internals of the parser in action, set this to true +PHPDOCUMENTOR_DEBUG = false +;; set to true if you want to eliminate extra whitespace in doc comments (slows things down quite a bit) +PHPDOCUMENTOR_KILL_WHITESPACE = false + +[_phpDocumentor_options] +;; this is the value that will be displayed as the root directory +Program_Root = +;; uncomment this to set the path phpDocumentor looks in to find user files +;userdir = user/ + +;; Use useconfig if you want to be able to run phpdoc with no command-line options (!!) +;; change the value of useconfig to an .ini file that is in users/ (like greg.ini) +;[_phpDocumentor_setting] +;useconfig = default + +[_phpDocumentor_phpfile_exts] +php +php3 +php4 +phtml +inc + +;; deprecated in 1.2 +;; this list is informational only - the following tags will be parsed as +;; having meaning, everything else will be treated as text by the output +;; converter, meaning in the HTML converter, all other tags will be htmlentitied +;[_phpDocumentor_html_allowed] +;ul +;ol +;li +;p +;strong +;pre +;a +;code +;br +;var +;samp +;kbd + +[_phpDocumentor_tags_allowed] +abstract +access +author +category +copyright +;; for Zend IDE support - minimal at best +desc +deprec +deprecated +example +exception +filesource +final +global +ignore +internal +license +link +magic +name +package +param +parameter +return +;; alias for @return +returns +see +since +source +static +staticvar +subpackage +throws +todo +TODO +tutorial +uses +var +version +;; compat tags, things wont parse right in incorrectly documented code without them +;; hopefully better error handling in handleDockeyword allows these to go away +;; this is a dumb tag included for pear compatability see bug# 558028 +extends +private +public + +[_phpDocumentor_inline_doc_tags_allowed] +example +inheritdoc +internal +link +source +tutorial + +[_phpDocumentor_inline_tutorial_tags_allowed] +category +example +id +link +toc +tutorial + +;; custom files to include in RIC +;; these MUST be in upper-case +[_phpDocumentor_RIC_files] +README +INSTALL +CHANGELOG +FAQ +NEWS diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Classes.inc b/buildscripts/PhpDocumentor/phpDocumentor/Classes.inc new file mode 100644 index 00000000..d4f29745 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Classes.inc @@ -0,0 +1,1068 @@ + + * @since 1.0rc1 + * @version $Id: Classes.inc,v 1.1 2005/10/17 18:36:55 jeichorn Exp $ + */ +/** + * Intermediate class parsing structure. + * + * The {@link phpDocumentor_IntermediateParser} class uses this class and its + * cousin, {@link ProceduralPages} to organize all parsed source code elements. + * Data is fed to each immediately after it is parsed, and at conversion time, + * everything is organized. + * + * The Classes class is responsible for all inheritance, including resolving + * name conflicts between classes, determining which classes extend other + * classes, and is responsible for all inheritance of documentation. + * {@internal + * This structure parses classes, vars and methods by file, and then iterates + * over the class tree to set up inheritance. The {@link Inherit()} + * method is the meat of the class, and processes the class trees from root to + * branch, ensuring that parsing order is unimportant.}} + * @package phpDocumentor + * @author Greg Beaver + * @since 1.0rc1 + * @version $Id: Classes.inc,v 1.1 2005/10/17 18:36:55 jeichorn Exp $ + */ +class Classes +{ + /**#@+ + * @access private + */ + /** + * file being parsed, used in every add function to match up elements with + * the file that contains them + * + * This variable is used during parsing to associate class elements added + * to the data structures that contain them with the file they reside in + * @see addClass(), addMethod(), addVar(), nextFile() + * @var string + */ + var $curfile; + /** + * class being parsed, used to match up methods and vars with their parent + * class + * + * This variable is used during parsing to associate class elements added + * to the data structures that contain them with the file they reside in + * @see addMethod(), addVar() + * @var string + */ + var $curclass; + + /** + * Used when a definite match is made between a parent class and a child + * class + * + * This variable is used in post-parsing. + * + * Format: array(parent => array(parentfile => array(child => childfile))) + * @var array + */ + var $definitechild; + /** + * array of parsed classes organized by the name of the file that contains + * the class. + * + * Format: + * array(filename => array(classname => {@link parserClass})) + * @var array + */ + var $classesbyfile = array(); + /** + * array of file names organized by classes that are in the file. + * + * This structure is designed to handle name conflicts. Two files can + * contain classes with the same name, and this array will record both + * filenames to help control linking and inheritance errors + * + * Format:
+     * array(classname => array(name of file containing classname,
+     *                          name of file 2 containing classname...)
+ * @var array + */ + var $classesbynamefile = array(); + /** + * array of parsed methods organized by the file that contains them. + * + * Format:
+     * array(filename => array(classname => array({@link parserMethod} 1, 
+     *                                            {@link parserMethod} 2,...))
+ * @var array + */ + var $methodsbyfile = array(); + /** + * array of parsed vars organized by the file that contains them. + * + * Format: + * array(filename => array(classname => array({@link parserVar} 1, {@link parserVar} 2,...)) + * @var array + */ + var $varsbyfile = array(); + /** + * array of parsed class constants organized by the file that contains them. + * + * Format: + * array(filename => array(classname => array({@link parserConst} 1, {@link parserConst} 2,...)) + * @var array + */ + var $constsbyfile = array(); + /** + * keeps track of extend declarations by file, used to find inheritance + * + * Format: + * array(filename => array(classname => parentclassname)) + * @var array + */ + var $extendsbyfile = array(); + /** + * Keeps track of child classes by file. + * Since phpDocumentor can document collections of files that contain name + * conflicts (PHP would give a fatal error), it + * is impossible to assume a class that declares "extends foo" necessarily + * extends the class foo in file X. It could be an + * extended class of class foo in file Y. Because of this, phpDocumentor + * relies on packaging to resolve the name conflict + * This array keeps track of the packages of a child class + * + * Format: + * array(parentclassname => array(filename => array(childclassname => + * array(packagename, packagename))) + * @var array + */ + var $classchildrenbyfile = array(); + /** + * Keeps track of class packages found in a file. + * This is used in {@link getParentClass()} to determine the number of + * packages in a file, in order to resolve inheritance issues + * Format: array(filename => array(packagename1, packagename2,...)) + * @var array + */ + var $classpackagebyfile = array(); + /** + * a tree of class inheritance by name. + * + * format:
+     * array(childname => parentname,
+     *       childname1 => parentname1,
+     *       rootname => 0, ...
+     *      )
+ * @var array + * @see Converter::generateSortedClassTreeFromClass() + */ + var $classparents = array(); + /** + * Keeps track of package and subpackage for each class name, organized + * by package + * + * Format:
+     * array(classname => array(path => array(package,subpackage),
+     *                          path2 => array(package,subpackage),...))
+ * @var array + */ + var $classpathpackages = array(); + /** + * used to delete duplicates in the same package to avoid documentation errors + * + * Specifically used in {@link Converter::checkKillClass()} + */ + var $killclass = array(); + /** + * array of methods by package and class + * + * format:
+     * array(packagename =>
+     *         array(classname =>
+     *               array(methodname1 => {@link parserMethod} class,
+     *                     methodname2 => {@link parserMethod} class,...)
+     *                      )
+     *              )
+     *      )
+ * @var array + * @see Converter + */ + var $methods = array(); + + /** + * array of class variables by package and class + * + * format:
+     * array(packagename =>
+     *         array(classname =>
+     *                array(variablename1 => {@link parserVar} class,
+     *                      variablename2 => {@link parserVar} class,...
+     *                     )
+     *              )
+     *      )
+ * @var array + * @see Converter + */ + var $vars = array(); + + /** + * array of class variables by package and class + * + * format:
+     * array(packagename =>
+     *         array(classname =>
+     *                array(constname1 => {@link parserConst} class,
+     *                      constname2 => {@link parserConst} class,...
+     *                     )
+     *              )
+     *      )
+ * @var array + * @see Converter + */ + var $consts = array(); + /** + * Reverse class_packages_by_file, used to prevent duplicates + * @var array Format: array(packagename => 1) + */ + var $revcpbf = array(); + /** + * All classes with no parents (no extends clause) are tracked in this array + * by the file that contains them. + * + * Format:
+     * array(classname => array(name of file1 that contains root classname,
+     *                          name of file2 that contains root classname,...))
+ * @var array + */ + var $roots = array(); + + /** + * array of all files that contain classes with the same name + * @var array Format: (classname => array(path1, path2,...)) + */ + var $potentialclassconflicts = array(); + + /** + * array of all inter-package name conflicts of classes + * + * This array allows documentation of PHP namespace conflicts that would + * occur should a user try to include these files in the same file + * @var array Format: (classname => array(path1, path2,...)) + */ + var $classconflicts = array(); + /**#@-*/ + /** + * While parsing, add a class to the list of parsed classes + * + * sets up the {@link $classesbyfile, $classesbynamefile, $extendsbyfile}, + * {@link $classchildrenbyfile, $roots} arrays, and sets {@link $curclass} + * @param parserClass &$element element is a {@link parserClass} + * @uses addPackageToFile() marks the current class's package as being + * present in a file + */ + function addClass(&$element) + { + $this->curclass = $element->getName(); + $element->curfile = $this->curfile; + if (isset($this->classesbyfile[$this->curfile][$this->curclass])) + { + addWarning(PDERROR_ELEMENT_IGNORED,'class',$this->curclass,$this->curfile); + $this->curclass = false; + return; + } + $this->classesbyfile[$this->curfile][$this->curclass] = $element; + $this->classesbynamefile[$this->curclass][] = $this->curfile; + $this->extendsbyfile[$this->curfile][$this->curclass] = $element->getExtends(); + $this->classchildrenbyfile[$element->getExtends()][$this->curfile][$this->curclass][] = $element->docblock->package; + if ($element->docblock->getExplicitPackage()) + $this->addPackageToFile($element->docblock->package); + if (!$element->getExtends()) + { + $this->roots[$this->curclass][] = $this->curfile; + } + } + + /** + * While parsing, add a method to the list of parsed methods + * + * sets up the {@link $methodsbyfile} array using {@link $curfile} and + * {@link $curclass} + * @param parserMethod &$element element is a {@link parserMethod} + */ + function addMethod(&$element) + { + if (!$this->curclass) return; + $this->methodsbyfile[$this->curfile][$this->curclass][] = $element; + } + + /** + * While parsing, add a variable to the list of parsed variables + * + * sets up the {@link $varsbyfile} array using {@link $curfile} and {@link $curclass} + * @param parserVar &$element element is a {@link parserVar} + */ + function addVar(&$element) + { + if (!$this->curclass) return; + $this->varsbyfile[$this->curfile][$this->curclass][] = $element; + } + + /** + * While parsing, add a variable to the list of parsed variables + * + * sets up the {@link $constsbyfile} array using {@link $curfile} and {@link $curclass} + * @param parserConst &$element element is a {@link parserConst} + */ + function addConst(&$element) + { + if (!$this->curclass) return; + $this->constsbyfile[$this->curfile][$this->curclass][] = $element; + } + + /** + * Prepare to parse a new file + * + * sets {@link $curfile} to $file and {@link $curclass} to false (no class being parsed) + * @param string $file file currently being parsed + */ + function nextFile($file) + { + $this->curfile = $file; + $this->curclass = false; + } + + /** + * Mark a package as being used in a class + * + * {@source} + * @param string $package package name + */ + function addPackageToFile($package) + { + if (!isset($this->revcpbf[$this->curfile][$package])) + $this->classpackagebyfile[$this->curfile][] = $package; + $this->revcpbf[$this->curfile][$package] = 1; + } + + /** + * Find the parent class of $class, and set up structures to note this fact + * + * Modifies the {@link parserClass} element in {@link $classesbyfile} to use + * the parent's package, and inherit methods/vars + * @param string $class child class to find parent class + * @param string $file file child class is located in + * @uses $definitechild if a match is made between a parent class and parameter + * $class in file $file, then definitechild is set here + * @uses getParentClass() to find the parent class + */ + function setClassParent($class,$file) + { + if (is_array($par = $this->getParentClass($class,$file))) + { +// phpDocumentor_out("$file class $class extends ".$par[1]." file ".$par[0]."\n"); + $this->classesbyfile[$file][$class]->setParent($par[1],$par[0],$this); + $this->definitechild[$par[1]][$par[0]][$class] = $file; + } else + { + $this->classesbyfile[$file][$class]->setParentNoClass($par); + } + } + + /** + * Main processing engine for setting up class inheritance. + * + * This function uses {@link $roots} to traverse the inheritance tree via + * {@link processChild()} and returns the data structures + * phpDocumentor_IntermediateParser needs to convert parsed data + * to output using {@link phpDocumentor_IntermediateParser::Convert()} + * @param phpDocumentor_IntermediateParser + * @uses processChild() set up inheritance + */ + function Inherit(&$render) + { + phpDocumentor_out("\nProcessing Class Inheritance\n\n"); + flush(); + phpDocumentor_out("\nProcessing Root Trees\n\n"); + flush(); + foreach($this->roots as $class => $files) + { + for ($i=0; $iprocessChild($render,$class,$files[$i]); + } + } + if (0) + foreach($this->classesbyfile as $i => $j) + { + foreach($j as $k => $m) + { + var_dump($i,$k); + if ($i == 'iConverter') + { + var_dump($j); + } + } + } + phpDocumentor_out("\nProcessing leftover classes (classes that extend root classes not found in the same package)\n"); + flush(); + foreach($this->classesbyfile as $i => $j) + { + foreach($j as $k => $m) + { + $this->processChild($render,$k,$i,true); + } + } + phpDocumentor_out("done processing leftover classes\n"); + flush(); + $this->setupClassConflicts(); + } + + /** + * Transfers actual conflicts from {@link $potentialClassconflicts} to + * {@link $classconflicts} + * @access private + * @uses $potentialclassconflicts transfers values to {@link $classconflicts} + */ + function setupClassConflicts() + { + foreach($this->potentialclassconflicts as $class => $paths) + { + if (count($paths) - 1) + { //conflict + $package = array(); + foreach($paths as $path) + { + // create a list of conflicting classes in each package + if (isset($this->classpathpackages[$class][$path])) + $package[$this->classpathpackages[$class][$path][0]][] = $path; + } + foreach($package as $pathpackages) + { + // if at least 2 functions exist in the same package, delete all but the first one and add warnings + if (count($pathpackages) - 1) + { + for($i=1; $i < count($pathpackages); $i++) + { + if (isset($this->classesbyfile[$pathpackages[$i]])) + { + addWarning(PDERROR_ELEMENT_IGNORED,'class',$class,$pathpackages[$i]); + $this->killClass($class,$pathpackages[$i]); + $oth = array_flip($paths); + unset($paths[$oth[$pathpackages[$i]]]); + } + } + } + } + $this->classconflicts[$class] = $paths; + } + } + } + + /** + * If a package contains two classes with the same name, this function finds + * that conflict + * + * Returns the {@link $classconflicts} entry for class $class, minus its own path + * @return mixed returns false if no conflicts, or an array of paths containing conflicts + */ + function getConflicts($class) + { + if (!isset($this->classconflicts[$class])) return false; + $a = array(); + foreach($this->classconflicts[$class] as $conflict) + { + $a[$this->classesbyfile[$conflict][$class]->docblock->package] = $this->classesbyfile[$conflict][$class]; + } + return $a; + } + + /** + * sets up {@link $killclass} for use by Converter::checkKillClass() + * @access private + */ + function killClass($class,$path) + { + $this->killclass[$class][$path] = true; + } + + /** + * This function recursively climbs up the class tree, setting inherited + * information like package and adds the elements to phpDocumentor_IntermediateParser. + * + * Using structures defined in {@link Classes}, the function first sets package information, + * and then seeks out child classes. + * It uses 3 tests to determine whether a class is a child class. + *
    + *
  1. child class is in the same file as the parent class and extends parent class
  2. + *
  3. child class is in a different file and specifies the parent's @package in its docblock
  4. + *
  5. child class is in a different file and is in a different @package, with one possible parent class
  6. + *
+ * @param phpDocumentor_IntermediateParser &$render + * @param string $class class to process + * @param string $file name of file $class is located in + * @param boolean $furb flag used privately to control informational output while parsing + * (used when processing leftover classes in {@link Inherit()} + * @global string default package, usually "default" + */ + function processChild(&$render,$class,$file,$furb = false) + { + global $phpDocumentor_DefaultPackageName; + if (isset($this->classesbyfile[$file][$class]->processed)) return; + $this->potentialclassconflicts[$class][] = $file; + if ($furb) phpDocumentor_out("Processing $class in file $file\n"); + flush(); + $this->classesbyfile[$file][$class]->processed = true; + $db = $this->classesbyfile[$file][$class]; + $render->addUses($db,$file); + if (!$render->parsePrivate) + { + // if this class has an @access private, and parse private is disabled, remove it + if ($db->docblock->hasaccess) + { + $aaa = $db->docblock->getKeyword('access'); + if (is_object($aaa) && $aaa->getString() == 'private') + { + if (isset($this->varsbyfile[$file]) && isset($this->varsbyfile[$file][$class])) + { + unset($this->varsbyfile[$file][$class]); + } + if (isset($this->methodsbyfile[$file]) && isset($this->methodsbyfile[$file][$class])) + { + unset($this->methodsbyfile[$file][$class]); + } + if (isset($this->constsbyfile[$file]) && isset($this->constsbyfile[$file][$class])) + { + unset($this->constsbyfile[$file][$class]); + } + $this->classesbyfile[$file][$class]->ignore = true; + // if this is a root class, remove it from the roots array + if (isset($this->roots[$class])) + foreach($this->roots[$class] as $i => $files) + { + // find the file kkey and unset + if ($files == $file) unset($this->roots[$class][$i]); + } + // if this is a child, remove it from the list of child classes of its parent + if ($db->getExtends()) unset($this->classchildrenbyfile[$db->getExtends()][$file]); + return; + } + } + } + if ($render->packageoutput) + { + if (!in_array($db->docblock->package,$render->packageoutput)) + { + if (isset($this->varsbyfile[$file]) && isset($this->varsbyfile[$file][$class])) + { + unset($this->varsbyfile[$file][$class]); + } + if (isset($this->methodsbyfile[$file]) && isset($this->methodsbyfile[$file][$class])) + { + unset($this->methodsbyfile[$file][$class]); + } + if (isset($this->constsbyfile[$file]) && isset($this->constsbyfile[$file][$class])) + { + unset($this->constsbyfile[$file][$class]); + } + $this->classesbyfile[$file][$class]->ignore = true; + if (isset($this->roots[$class])) + foreach($this->roots[$class] as $i => $files) + { + if ($files == $file) unset($this->roots[$class][$i]); + } + if ($db->getExtends()) unset($this->classchildrenbyfile[$db->getExtends()][$file]); + return; + } + } + $this->setClassParent($class,$file); + $db = $this->classesbyfile[$file][$class]; + if ($furb && !is_array($db->parent)) + { +// debug("furb adding $class $file to roots"); + $this->roots[$class][] = $file; + } + // fix for 591396 + if (!$db->docblock->getExplicitPackage()) + { + $a = $render->proceduralpages->pagepackages[$file]; + if ($a[0] != $phpDocumentor_DefaultPackageName) + { + // inherit page package + $this->classesbyfile[$file][$class]->docblock->package = $a[0]; + } + } + if ($this->classesbyfile[$file][$class]->docblock->package == $render->proceduralpages->pagepackages[$file][0]) + { + if ($this->classesbyfile[$file][$class]->docblock->subpackage == '') + $this->classesbyfile[$file][$class]->docblock->subpackage = $render->proceduralpages->pagepackages[$file][1]; + } + $db = $this->classesbyfile[$file][$class]; + $render->addPackageParent($db); + $render->addPageIfNecessary($file, $db); + if ($access = $db->docblock->getKeyword('access')) + { + if (!is_string($access) && is_object($access)) $access = $access->getString(); + if (!is_string($access)) $access = 'public'; + if (($access == 'private') && (!$render->parsePrivate)) + { + if (isset($this->varsbyfile[$file]) && isset($this->varsbyfile[$file][$class])) + foreach($this->varsbyfile[$file][$class] as $i => $vr) + { + $vr->docblock->addKeyword('access','private'); + $this->varsbyfile[$file][$class][$i] = $vr; + } + if (isset($this->methodsbyfile[$file]) && isset($this->methodsbyfile[$file][$class])) + foreach($this->methodsbyfile[$file][$class] as $i => $vr) + { + $vr->docblock->addKeyword('access','private'); + $this->methodsbyfile[$file][$class][$i] = $vr; + } + if (isset($this->constsbyfile[$file]) && isset($this->constsbyfile[$file][$class])) + foreach($this->constsbyfile[$file][$class] as $i => $vr) + { + $vr->docblock->addKeyword('access','private'); + $this->constsbyfile[$file][$class][$i] = $vr; + } + } + } + $this->classpathpackages[$class][$file] = array($db->docblock->package,$db->docblock->subpackage); + if ($db->docblock->getExplicitPackage()) + $render->proceduralpages->addClassPackageToFile($file,$db->docblock->package,$db->docblock->subpackage); + $render->addElementToPage($db,$file); + if (isset($this->varsbyfile[$file]) && isset($this->varsbyfile[$file][$class])) + foreach($this->varsbyfile[$file][$class] as $i => $vr) + { + $vr->docblock->package = $db->docblock->package; + $vr->docblock->subpackage = $db->docblock->subpackage; + $render->addElementToPage($vr,$file); + $render->addUses($vr,$file); + $this->varsbyfile[$file][$class][$i] = $vr; + $this->vars[$db->docblock->package][$class][$vr->getName()] = $vr; + } + if (isset($this->methodsbyfile[$file]) && isset($this->methodsbyfile[$file][$class])) + foreach($this->methodsbyfile[$file][$class] as $i => $vr) + { + $vr->docblock->package = $db->docblock->package; + $vr->docblock->subpackage = $db->docblock->subpackage; + $render->addElementToPage($vr,$file); + $render->addUses($vr,$file); + $this->methodsbyfile[$file][$class][$i] = $vr; + $this->methods[$db->docblock->package][$class][$vr->getName()] = $vr; + } + if (isset($this->constsbyfile[$file]) && isset($this->constsbyfile[$file][$class])) + foreach($this->constsbyfile[$file][$class] as $i => $vr) + { + $vr->docblock->package = $db->docblock->package; + $vr->docblock->subpackage = $db->docblock->subpackage; + $render->addElementToPage($vr,$file); + $render->addUses($vr,$file); + $this->constsbyfile[$file][$class][$i] = $vr; + $this->methods[$db->docblock->package][$class][$vr->getName()] = $vr; + } + $this->classpackages[$class][] = array($db->docblock->package,$db->docblock->subpackage); + if (is_array($db->parent)) + $this->classparents[$db->docblock->package][$class] = $db->parent[1]; + else + $this->classparents[$db->docblock->package][$class] = $db->getExtends(); + if (is_array($db->parent)) + { + $z = $this->getClass($db->parent[1],$db->parent[0]); + $this->classchildren[$z->docblock->package][$db->parent[1]][] = $db; + } + if (isset($this->classchildrenbyfile[$class])) + { + foreach($this->classchildrenbyfile[$class] as $childfile => $other) + { + // test 1, inherits in same file (must be same package) + if ($childfile == $file) + { + foreach($other as $child => $packages) + { +// debug("parent $class same file $child"); + $this->processChild($render,$child,$childfile); + $x = $this->getClass($child,$childfile); + if ($x->docblock->package != $GLOBALS['phpDocumentor_DefaultPackageName']) + { + // child package need root for class trees + if ($x->docblock->package != $db->docblock->package) + { +// debug("adding $child in $childfile 1"); + $this->roots[$child][] = $childfile; + } + } + } + } else + { + // test 2, different file, same package + foreach($other as $child => $packages) + { + for($j=0; $jclassesbyfile[$file][$class]->docblock->package == $packages[$j]) + { + $this->processChild($render,$child,$childfile); +// debug("$childfile diff file $child, parent $class, same package ".$packages[$j]); + } else + { + // test 3, different file, different package, only 1 parent is possible + if (isset($this->classesbynamefile[$child])) + { + // 1 possible parent + if (count($this->classesbynamefile[$class]) == 1) + { +// debug("$childfile diff file $child, diff package, 1 possible parent root $class"); + $this->processChild($render,$child,$childfile); + $x = $this->getClass($child,$childfile); + if ($x->docblock->package != $GLOBALS['phpDocumentor_DefaultPackageName']) + { + // child package need root for class trees + if ($x->docblock->package != $db->docblock->package) + { +// debug("adding roots $child in $childfile 2"); + $this->roots[$child][] = $childfile; + } + } + } + } + } + } + } + } + } + } + } + + /** + * Get the parserClass representation of a class from its name and file + * @return parserClass + * @param string $class classname + * @param string $file file classname is located in + */ + function &getClass($class, $file) + { +// debug("getClass called with class $class file $file"); + return $this->classesbyfile[$file][$class]; + } + + /** + * Used by {@link parserData::getClasses()} to retrieve classes defined in file $path + * + * retrieves the array entry from {@link $classesbyfile} for $path + * @param string $path full path to filename + * @return mixed returns false if no classes defined in the file, otherwise returns an array of {@link parserClass}es + */ + function getClassesInPath($path) + { + if (!isset($this->classesbyfile[$path])) return false; + return $this->classesbyfile[$path]; + } + + /** + * called by {@link parserClass::hasMethods()}. Should not be directly called + * @access private + * @param string $file + * @param string $class + */ + function hasMethods($file,$class) + { + return isset($this->methodsbyfile[$file][$class]); + } + + /** + * called by {@link parserClass::hasConsts()}. Should not be directly called + * @access private + * @param string $file + * @param string $class + */ + function hasConsts($file,$class) + { + return isset($this->constsbyfile[$file][$class]); + } + + /** + * called by {@link parserClass::hasVars()}. Should not be directly called + * @access private + * @param string $file + * @param string $class + */ + function hasVars($file, $class) + { + return isset($this->varsbyfile[$file][$class]); + } + + /** + * called by {@link parserClass::hasMethod()}. Should not be directly called + * @param string $file + * @param string $class + * @param string $name method name + * @access private + */ + function hasMethod($class, $file, $name) + { + if (!$this->hasMethods($file, $class)) return false; + for($i=0; $imethodsbyfile[$file][$class]); $i++) + { + if ($this->methodsbyfile[$file][$class][$i]->getName() == $name) return true; + } + return false; + } + + /** + * called by {@link parserClass::hasVar()}. Should not be directly called + * @param string $file + * @param string $class + * @param string $name var name + * @access private + */ + function hasVar($class, $file, $name) + { + if (!$this->hasVars($file, $class)) return false; + for($i=0; $ivarsbyfile[$file][$class]); $i++) + { + if ($this->varsbyfile[$file][$class][$i]->getName() == $name) return true; + } + return false; + } + + /** + * called by {@link parserClass::hasConst()}. Should not be directly called + * @param string $file + * @param string $class + * @param string $name var name + * @access private + */ + function hasConst($class, $file, $name) + { + if (!$this->hasConsts($file, $class)) return false; + for($i=0; $iconstsbyfile[$file][$class]); $i++) + { + if ($this->constsbyfile[$file][$class][$i]->getName() == $name) return true; + } + return false; + } + + /** + * called by {@link parserClass::getMethods()}. Should not be directly called + * @access private + * @param string $class + * @param string $file + */ + function &getMethods($class, $file) + { + if (!isset($this->methodsbyfile[$file][$class])) return false; + return $this->methodsbyfile[$file][$class]; + } + + /** + * called by {@link parserClass::getVars()}. Should not be directly called + * @access private + * @param string $class + * @param string $file + */ + function &getVars($class, $file) + { + if (!isset($this->varsbyfile[$file][$class])) return false; + return $this->varsbyfile[$file][$class]; + } + + /** + * called by {@link parserClass::getConsts()}. Should not be directly called + * @access private + * @param string $class + * @param string $file + */ + function &getConsts($class, $file) + { + if (!isset($this->constsbyfile[$file][$class])) return false; + return $this->constsbyfile[$file][$class]; + } + + /** + * called by {@link parserClass::getMethod()}. Should not be directly called + * @param string $class + * @param string $file + * @param string $name method name + * @access private + */ + function getMethod($class, $file, $name) + { + if (!$this->hasMethod($class, $file, $name)) return false; + for($i=0; $imethodsbyfile[$file][$class]); $i++) + { + if ($this->methodsbyfile[$file][$class][$i]->getName() == $name) return $this->methodsbyfile[$file][$class][$i]; + } + } + + /** + * called by {@link parserClass::getVar()}. Should not be directly called + * @param string $class + * @param string $file + * @param string $name var name + * @access private + */ + function getVar($class, $file, $name) + { + if (!$this->hasVar($class, $file, $name)) return false; + for($i=0; $ivarsbyfile[$file][$class]); $i++) + { + if ($this->varsbyfile[$file][$class][$i]->getName() == $name) return $this->varsbyfile[$file][$class][$i]; + } + } + + /** + * called by {@link parserClass::getConst()}. Should not be directly called + * @param string $class + * @param string $file + * @param string $name var name + * @access private + */ + function getConst($class, $file, $name) + { + if (!$this->hasConst($class, $file, $name)) return false; + for($i=0; $iconstsbyfile[$file][$class]); $i++) + { + if ($this->constsbyfile[$file][$class][$i]->getName() == $name) return $this->constsbyfile[$file][$class][$i]; + } + } + + /** + * Search for a class in a package + * @return mixed returns false if no class in $package, otherwise returns a {@link parserClass} + * @param string $class classname + * @param string $package package classname is in + */ + function &getClassByPackage($class,$package) + { + if (!isset($this->classesbynamefile[$class])) + { +// addWarning(PDERROR_CLASS_NOT_IN_PACKAGE,$class,$package); // removed, too many warnings, not very useful + return false; + } + for($i=0; $i < count($this->classesbynamefile[$class]); $i++) + { + $cls = $this->classesbyfile[$this->classesbynamefile[$class][$i]][$class]; + $pkg = $cls->getPackage(); + if ($pkg == $package) + return $cls; + } +// addWarning(PDERROR_CLASS_NOT_IN_PACKAGE,$class,$package); + return false; + } + + /** + * Find the parent class of a class in file $file + * uses 3 tests to find the parent classname: + *
    + *
  1. only one class with the parent classname
  2. + *
  3. more than one class, but only one in the same file as the child
  4. + *
  5. only one parent class in the same package as the child
  6. + *
+ * @return mixed false if no parent class, a string if no parent class found by that name, + * and an array(file parentclass is in,parentclassname) + */ + function getParentClass($class,$file) + { + if (!isset($this->classesbyfile[$file][$class])) + { + return false; + } + $element = $this->classesbyfile[$file][$class]; + if (!($ex = $element->getExtends())) return false; + // first check to see if there is one and only one class with the parent class's name + if (isset($this->classesbynamefile[$ex])) + { + if (count($this->classesbynamefile[$ex]) == 1) + { + if ($this->classesbyfile[$this->classesbynamefile[$ex][0]][$ex]->ignore) return $ex; + return array($this->classesbynamefile[$ex][0],$ex); + } else + { + // next check to see if there is a parent class in the same file + if (isset($this->classesbyfile[$file][$ex])) + { + if ($this->classesbyfile[$file][$ex]->ignore) return $ex; + return array($file,$ex); + } + // next check to see if there is only one package used in the file, try to resolve it that way + if (isset($this->classpackagebyfile[$file])) + { + if (count($this->classpackagebyfile[$file]) == 1) + { + for($i=0;$iclassesbynamefile[$ex]);$i++) + { + if ($this->classesbyfile[$this->classesbynamefile[$ex][$i]][$ex]->getPackage() == $this->classpackagebyfile[$file][0]) + { + if ($this->classesbyfile[$this->classesbynamefile[$ex][$i]][$ex]->ignore) return $ex; + return array($this->classesbynamefile[$ex][$i],$ex); + } + } + } + } + // name conflict + addWarning(PDERROR_INHERITANCE_CONFLICT, $class, $file, $ex); + return $ex; + } + } else + { + addWarning(PDERROR_PARENT_NOT_FOUND, $class, $ex); + return $ex; + } + } + + /** + * Get a list of all root classes indexed by package. Used to generate + * class trees by {@link Converter} + * @return array array(package => array(rootclassname, rootclassname,...),...) + */ + function getRoots() + { + $roots = array(); + foreach($this->roots as $class => $files) + { + if (count($files)) + { + foreach($files as $i => $boofou) + { + $x = $this->getClass($class,$files[$i]); + $roots[$x->getPackage()][] = $class; + } + } + } + foreach($roots as $package => $root) + { + usort($roots[$package],"strnatcasecmp"); + } + return $roots; + } + + /** + * Get all classes confirmed in parsing to be descended class $parclass in file $file + * @return mixed either false if no children, or array of format + * array(childname => childfile,childname2 => childfile2,...) + * @param string $parclass name of parent class + * @param string $file file parent class is found in + * @see parserClass::getChildClassList() + * @uses $definitechild + */ + function getDefiniteChildren($parclass,$file) + { + if (isset($this->definitechild[$parclass][$file])) return $this->definitechild[$parclass][$file]; + return false; + } +} +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converter.inc b/buildscripts/PhpDocumentor/phpDocumentor/Converter.inc new file mode 100644 index 00000000..5b499d65 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converter.inc @@ -0,0 +1,5189 @@ + + * @since 1.0rc1 + * @version $Id: Converter.inc,v 1.5 2005/11/28 07:27:59 cellog Exp $ + */ +/** + * Smarty template files + */ +include_once("phpDocumentor/Smarty-2.6.0/libs/Smarty.class.php"); +/** + * Base class for all output converters. + * + * The Converter marks the final stage in phpDocumentor. phpDocumentor works + * in this order: + * + *
Parsing => Intermediate Parsing organization => Conversion to output
+ * + * A Converter takes output from the {@link phpDocumentor_IntermediateParser} and + * converts it to output. With version 1.2, phpDocumentor includes a variety + * of output converters: + *
    + *
  • {@link HTMLframesConverter}
  • + *
  • {@link HTMLSmartyConverter}
  • + *
  • {@link PDFdefaultConverter}
  • + *
  • {@link CHMdefaultConverter}
  • + *
  • {@link CSVdia2codeConverter}
  • + *
  • {@link XMLDocBookConverter}
  • + *
+ * {@internal + * The converter takes output directly from {@link phpDocumentor_IntermediateParser} + * and using {@link walk()} or {@link walk_everything} (depending on the value of + * {@link $sort_absolutely_everything}) it "walks" over an array of phpDocumentor elements.}} + * + * @package Converters + * @abstract + * @author Greg Beaver + * @since 1.0rc1 + * @version $Id: Converter.inc,v 1.5 2005/11/28 07:27:59 cellog Exp $ + */ +class Converter +{ + /** + * output format of this converter + * + * in Child converters, this will match the first part of the -o command-line + * as in -o HTML:frames:default "HTML" + * @tutorial phpDocumentor.howto.pkg#using.command-line.output + * @var string + */ + var $outputformat = 'Generic'; + /** + * package name currently being converted + * @var string + */ + var $package = 'default'; + /** + * subpackage name currently being converted + * @var string + */ + var $subpackage = ''; + /** + * set to a classname if currently parsing a class, false if not + * @var string|false + */ + var $class = false; + /**#@+ + * @access private + */ + /** + * the workhorse of linking. + * + * This array is an array of link objects of format: + * [package][subpackage][eltype][elname] = descendant of {@link abstractLink} + * eltype can be page|function|define|class|method|var + * if eltype is method or var, the array format is: + * [package][subpackage][eltype][class][elname] + * @var array + * @see functionLink, pageLink, classLink, defineLink, methodLink, varLink, globalLink + */ + var $links = array(); + + /** + * the workhorse of linking, with allowance for support of multiple + * elements in different files. + * + * This array is an array of link objects of format: + * [package][subpackage][eltype][file][elname] = descendant of {@link abstractLink} + * eltype can be function|define|class|method|var + * if eltype is method or var, the array format is: + * [package][subpackage][eltype][file][class][elname] + * @var array + * @see functionLink, pageLink, classLink, defineLink, methodLink, varLink, globalLink + */ + var $linkswithfile = array(); + /**#@-*/ + /** + * set to value of -po commandline + * @tutorial phpDocumentor.howto.pkg#using.command-line.packageoutput + * @var mixed + */ + var $package_output; + + /** + * name of current page being converted + * @var string + */ + var $page; + + /** + * path of current page being converted + * @var string + */ + var $path; + + /** + * template for the procedural page currently being processed + * @var Smarty + */ + var $page_data; + + /** + * template for the class currently being processed + * @var Smarty + */ + var $class_data; + + /** + * current procedural page being processed + * @var parserPage + */ + var $curpage; + /** + * alphabetical index of all elements sorted by package, subpackage, page, + * and class. + * @var array Format: array(package => array(subpackage => array('page'|'class' => array(path|classname => array(element, element,...))))) + * @uses $sort_absolutely_everything if true, then $package_elements is used, + * otherwise, the {@link ParserData::$classelements} and + * {@link ParserData::$pageelements} variables are used + */ + var $package_elements = array(); + /** + * alphabetical index of all elements + * + * @var array Format: array(first letter of element name => array({@link parserElement} or {@link parserPage},...)) + * @see formatIndex(), HTMLframesConverter::formatIndex() + */ + var $elements = array(); + /** + * alphabetized index of procedural pages by package + * + * @see $leftindex + * @var array Format: array(package => array(subpackage => array({@link pageLink} 1,{@link pageLink} 2,...) + */ + var $page_elements = array(); + /** + * alphabetized index of defines by package + * + * @see $leftindex + * @var array Format: array(package => array(subpackage => array({@link defineLink} 1,{@link defineLink} 2,...) + */ + var $define_elements = array(); + /** + * alphabetized index of classes by package + * + * @see $leftindex + * @var array Format: array(package => array(subpackage => array({@link classLink} 1,{@link classLink} 2,...) + */ + var $class_elements = array(); + /** + * alphabetized index of global variables by package + * + * @see $leftindex + * @var array Format: array(package => array(subpackage => array({@link globalLink} 1,{@link globalLink} 2,...) + */ + var $global_elements = array(); + /** + * alphabetized index of functions by package + * + * @see $leftindex + * @var array Format: array(package => array(subpackage => array({@link functionLink} 1,{@link functionLink} 2,...) + */ + var $function_elements = array(); + /** + * alphabetical index of all elements, indexed by package/subpackage + * + * @var array Format: array(first letter of element name => array({@link parserElement} or {@link parserPage},...)) + * @see formatPkgIndex(), HTMLframesConverter::formatPkgIndex() + */ + var $pkg_elements = array(); + + /** + * alphabetical index of all elements on a page by package/subpackage + * + * The page itself has a link under ###main + * @var array Format: array(package => array(subpackage => array(path => array({@link abstractLink} descendant 1, ...))) + * @see formatLeftIndex() + */ + var $page_contents = array(); + + /** + * This determines whether the {@link $page_contents} array should be sorted by element type as well as alphabetically by name + * @see sortPageContentsByElementType() + * @var boolean + */ + var $sort_page_contents_by_type = false; + /** + * This is used if the content must be passed in the order it should be read, i.e. by package, procedural then classes + * + * This fixes bug 637921, and is used by {@link PDFdefaultConverter} + */ + var $sort_absolutely_everything = false; + /** + * alphabetical index of all methods and vars in a class by package/subpackage + * + * The class itself has a link under ###main + * @var array + * Format:
+     * array(package =>
+     *       array(subpackage =>
+     *             array(path =>
+     *                   array(class =>
+     *                         array({@link abstractLink} descendant 1, ...
+     *                        )
+     *                  )
+     *            )
+     *      )
+ * @see formatLeftIndex() + */ + var $class_contents = array(); + /** + * controls processing of elements marked private with @access private + * + * defaults to false. Set with command-line --parseprivate or -pp + * @var bool + */ + var $parseprivate; + /** + * controls display of progress information while parsing. + * + * defaults to false. Set to true for cron jobs or other situations where no visual output is necessary + * @var bool + */ + var $quietmode; + + /** + * directory that output is sent to. -t command-line sets this. + * @tutorial phpDocumentor.howto.pkg#using.command-line.target + */ + var $targetDir = ''; + + /** + * Directory that the template is in, relative to phpDocumentor root directory + * @var string + */ + var $templateDir = ''; + + /** + * Directory that the smarty templates are in + * @var string + */ + var $smarty_dir = ''; + + /** + * Name of the template, from last part of -o + * @tutorial phpDocumentor.howto.pkg#using.command-line.output + * @var string + */ + var $templateName = ''; + + /** + * full path of the current file being converted + */ + var $curfile; + + /** + * All class information, organized by path, and by package + * @var Classes + */ + var $classes; + + /** + * Hierarchy of packages + * + * Every package that contains classes may have parent or child classes + * in other packages. In other words, this code is legal: + * + * + * /** + * * @package one + * * / + * class one {} + * + * /** + * * @package two + * * / + * class two extends one {} + * + * + * In this case, package one is a parent of package two + * @var array + * @see phpDocumentor_IntermediateParser::$package_parents + */ + var $package_parents; + + /** + * Packages associated with categories + * + * Used by the XML:DocBook/peardoc2 converter, and available to others, to + * group many packages into categories + * @see phpDocumentor_IntermediateParser::$packagecategories + * @var array + */ + var $packagecategories; + + /** + * All packages encountered in parsing + * @var array + * @see phpDocumentor_IntermediateParser::$all_packages + */ + var $all_packages; + + /** + * A list of files that have had source code generated + * @var array + */ + var $sourcePaths = array(); + + /** + * Controls which of the one-element-only indexes are generated. + * + * Generation of these indexes for large packages is time-consuming. This is an optimization feature. An + * example of how to use this is in {@link HTMLframesConverter::$leftindex}, and in {@link HTMLframesConverter::formatLeftIndex()}. + * These indexes are intended for use as navigational aids through documentation, but can be used for anything by converters. + * @see $class_elements, $page_elements, $function_elements, $define_elements, $global_elements + * @see formatLeftIndex() + * @var array + */ + var $leftindex = array('classes' => true, 'pages' => true, 'functions' => true, 'defines' => true, 'globals' => true); + + /** @access private */ + var $killclass = false; + /** + * @var string + * @see phpDocumentor_IntermediateParser::$title + */ + var $title = 'Generated Documentation'; + + /** + * Options for each template, parsed from the options.ini file in the template base directory + * @tutorial phpDocumentor/tutorials.pkg#conversion.ppage + * @var array + */ + var $template_options; + + /** + * Tutorials and Extended Documentation parsed from a tutorials/package[/subpackage] directory + * @tutorial tutorials.pkg + * @access private + */ + var $tutorials = array(); + + /** + * tree-format structure of tutorials and their child tutorials, if any + * @var array + * @access private + */ + var $tutorial_tree = false; + + /** + * list of tutorials that have already been processed. Used by @link _setupTutorialTree() + * @var array + * @access private + */ + var $processed_tutorials; + + /** + * List of all @todo tags and a link to the element with the @todo + * + * Format: array(package => array(link to element, array(todo {@link parserTag},...)),...) + * @tutorial tags.todo.pkg + * @var array + */ + var $todoList = array(); + + /** + * Initialize Converter data structures + * @param array {@link $all_packages} value + * @param array {@link $package_parents} value + * @param Classes {@link $classes} value + * @param ProceduralPages {@link $proceduralpages} value + * @param array {@link $package_output} value + * @param boolean {@link $parseprivate} value + * @param boolean {@link $quietmode} value + * @param string {@link $targetDir} value + * @param string {@link $templateDir} value + * @param string (@link $title} value + */ + function Converter(&$allp, &$packp, &$classes, &$procpages, $po, $pp, $qm, $targetDir, $template, $title) + { + $this->all_packages = $allp; + $this->package_parents = $packp; + $this->package = $GLOBALS['phpDocumentor_DefaultPackageName']; + $this->proceduralpages = &$procpages; + $this->package_output = $po; + if (is_array($po)) + { + $a = $po[0]; + $this->all_packages = array_flip($po); + $this->all_packages[$a] = 1; + } + $this->parseprivate = $pp; + $this->quietmode = $qm; + $this->classes = &$classes; + $this->roots = $classes->getRoots(); + $this->title = $title; + $this->setTemplateDir($template); + $this->setTargetdir($targetDir); + } + + /** + * Called by IntermediateParser after creation + * @access private + */ + function setTutorials($tutorials) + { + $this->tutorials = $tutorials; + } + + /** + * @param pkg|cls|proc the tutorial type to search for + * @param tutorial name + * @param string package name + * @param string subpackage name, if any + * @return false|parserTutorial if the tutorial exists, return it + */ + function hasTutorial($type, $name, $package, $subpackage = '') + { + if (isset($this->tutorials[$package][$subpackage][$type][$name . '.' . $type])) + return $this->tutorials[$package][$subpackage][$type][$name . '.' . $type]; + return false; + } + + /** + * Called by {@link walk()} while converting, when the last class element + * has been parsed. + * + * A Converter can use this method in any way it pleases. HTMLframesConverter + * uses it to complete the template for the class and to output its + * documentation + * @see HTMLframesConverter::endClass() + * @abstract + */ + function endClass() + { + } + + /** + * Called by {@link walk()} while converting, when the last procedural page + * element has been parsed. + * + * A Converter can use this method in any way it pleases. HTMLframesConverter + * uses it to complete the template for the procedural page and to output its + * documentation + * @see HTMLframesConverter::endClass() + * @abstract + */ + function endPage() + { + } + + /** + * Called by {@link walk()} while converting. + * + * This method is intended to be the place that {@link $pkg_elements} is + * formatted for output. + * @see HTMLframesConverter::formatPkgIndex() + * @abstract + */ + function formatPkgIndex() + { + } + + /** + * Called by {@link walk()} while converting. + * + * This method is intended to be the place that {@link $elements} is + * formatted for output. + * @see HTMLframesConverter::formatIndex() + * @abstract + */ + function formatIndex() + { + } + + /** + * Called by {@link walk()} while converting. + * + * This method is intended to be the place that any of + * {@link $class_elements, $function_elements, $page_elements}, + * {@link $define_elements}, and {@link $global_elements} is formatted for + * output, depending on the value of {@link $leftindex} + * @see HTMLframesConverter::formatLeftIndex() + * @abstract + */ + function formatLeftIndex() + { + } + + /** + * Called by {@link parserSourceInlineTag::stringConvert()} to allow + * converters to format the source code the way they'd like. + * + * default returns it unchanged (html with xhtml tags) + * @param string output from highlight_string() - use this function to + * reformat the returned data for Converter-specific output + * @return string + * @deprecated in favor of tokenizer-based highlighting. This will be + * removed for 2.0 + */ + function unmangle($sourcecode) + { + return $sourcecode; + } + + /** + * Initialize highlight caching + */ + function startHighlight() + { + $this->_highlightCache = array(false, false); + $this->_appendHighlight = ''; + } + + function getHighlightState() + { + return $this->_highlightCache; + } + + function _setHighlightCache($type, $token) + { + $test = ($this->_highlightCache[0] === $type && $this->_highlightCache[1] == $token); + if (!$test) { + $this->_appendHighlight = $this->flushHighlightCache(); + } else { + $this->_appendHighlight = ''; + } + $this->_highlightCache = array($type, $token); + return $test; + } + + /** + * Return the close text for the current token + * @return string + */ + function flushHighlightCache() + { + $hc = $this->_highlightCache; + $this->_highlightCache = array(false, false); + if ($hc[0]) { + if (!isset($this->template_options[$hc[0]]['/'.$hc[1]])) { + return ''; + } + return $this->template_options[$hc[0]]['/'.$hc[1]]; + } + return ''; + } + + /** + * Used to allow converters to format the source code the way they'd like. + * + * default returns it unchanged. Mainly used by the {@link HighlightParser} + * {@internal + * The method takes information from options.ini, the template options + * file, specifically the [highlightSourceTokens] and [highlightSource] + * sections, and uses them to enclose tokens. + * + * {@source}}} + * @param integer token value from {@link PHP_MANUAL#tokenizer tokenizer constants} + * @param string contents of token + * @param boolean whether the contents are preformatted or need modification + * @return string + */ + function highlightSource($token, $word, $preformatted = false) + { + if ($token !== false) + { + if (!$preformatted) $word = $this->postProcess($word); + if (isset($this->template_options['highlightSourceTokens'][token_name($token)])) + { + if ($this->_setHighlightCache('highlightSourceTokens', token_name($token))) { + return $word; + } + $e = $this->_appendHighlight; + return $e . $this->template_options['highlightSourceTokens'][token_name($token)] . $word; + } else + { + $this->_setHighlightCache(false, false); + $e = $this->_appendHighlight; + return $e . $word; + } + } else + { + if (isset($this->template_options['highlightSource'][$word])) + { + $newword = ($preformatted ? $word : $this->postProcess($word)); + if ($this->_setHighlightCache('highlightSource', $word)) { + return $newword; + } + $e = $this->_appendHighlight; + return $e . $this->template_options['highlightSource'][$word] . $newword; + } else + { + $this->_setHighlightCache(false, false); + $e = $this->_appendHighlight; + return $e . ($preformatted ? $word : $this->postProcess($word)); + } + } + } + + /** + * Used to allow converters to format the source code of DocBlocks the way + * they'd like. + * + * default returns it unchanged. Mainly used by the {@link HighlightParser} + * {@internal + * The method takes information from options.ini, the template options + * file, specifically the [highlightDocBlockSourceTokens] section, and uses + * it to enclose tokens. + * + * {@source}}} + * @param string name of docblock token type + * @param string contents of token + * @param boolean whether the contents are preformatted or need modification + * @return string + */ + function highlightDocBlockSource($token, $word, $preformatted = false) + { + if (empty($word)) { + $this->_setHighlightCache(false, false); + $e = $this->_appendHighlight; + return $e . $word; + } + if (isset($this->template_options['highlightDocBlockSourceTokens'][$token])) + { + if (!$preformatted) $word = $this->postProcess($word); + if ($this->_setHighlightCache('highlightDocBlockSourceTokens', $token)) { + return $word; + } + $e = $this->_appendHighlight; + return $e . $this->template_options['highlightDocBlockSourceTokens'][$token] . $word; + } else { + $this->_setHighlightCache(false, false); + $e = $this->_appendHighlight; + return $e . ($preformatted ? $word : $this->postProcess($word)); + } + } + + /** + * Used to allow converters to format the source code of DocBlocks the way + * they'd like. + * + * default returns it unchanged. Mainly used by the {@link HighlightParser} + * {@internal + * The method takes information from options.ini, the template options + * file, specifically the [highlightDocBlockSourceTokens] section, and uses + * it to enclose tokens. + * + * {@source}}} + * @param string name of docblock token type + * @param string contents of token + * @param boolean whether the contents are preformatted or need modification + * @return string + */ + function highlightTutorialSource($token, $word, $preformatted = false) + { + if (empty($word)) { + $this->_setHighlightCache(false, false); + $e = $this->_appendHighlight; + return $e . $word; + } + if (isset($this->template_options['highlightTutorialSourceTokens'][$token])) + { + if (!$preformatted) $word = $this->postProcess($word); + if ($this->_setHighlightCache('highlightTutorialSourceTokens', $token)) { + return $word; + } + $e = $this->_appendHighlight; + return $e . $this->template_options['highlightTutorialSourceTokens'][$token] . $word; + } else { + $this->_setHighlightCache(false, false); + $e = $this->_appendHighlight; + return $e . ($preformatted ? $word : $this->postProcess($word)); + } + } + + /** + * Called by {@link parserReturnTag::Convert()} to allow converters to + * change type names to desired formatting + * + * Used by {@link XMLDocBookConverter::type_adjust()} to change true and + * false to the peardoc2 values + * @param string + * @return string + */ + function type_adjust($typename) + { + return $typename; + } + + /** + * Used to convert the {@}example} inline tag in a docblock. + * + * By default, this just wraps ProgramExample + * @see XMLDocBookpeardoc2Converter::exampleProgramExample + * @param string + * @param boolean true if this is to highlight a tutorial + * @return string + */ + function exampleProgramExample($example, $tutorial = false, $inlinesourceparse = null/*false*/, + $class = null/*false*/, $linenum = null/*false*/, $filesourcepath = null/*false*/) + { + return $this->ProgramExample($example, $tutorial, $inlinesourceparse, $class, $linenum, $filesourcepath); + } + + /** + * Used to convert the <> tag in a docblock + * @param string + * @param boolean true if this is to highlight a tutorial + * @return string + */ + function ProgramExample($example, $tutorial = false, $inlinesourceparse = null/*false*/, + $class = null/*false*/, $linenum = null/*false*/, $filesourcepath = null/*false*/) + { + if (tokenizer_ext) + { + $e = $example; + if (!is_array($example)) + { + $obj = new phpDocumentorTWordParser; + $obj->setup($example); + $e = $obj->getFileSource(); + if (!isset($e[0]) || !is_array($e[0][0]) || $e[0][0][0] != T_OPEN_TAG) + { + $example = "setup($example); + $e = $obj->getFileSource(); + unset($e[0]); + $e = array_values($e); + } + unset($obj); + } + $saveclass = $this->class; + $parser = new phpDocumentor_HighlightParser; + if (!isset($inlinesourceparse)) + { + $example = $parser->parse($e, $this, true); // force php mode + } else + { + if (isset($filesourcepath)) + { + $example = $parser->parse($e, $this, $inlinesourceparse, $class, $linenum, $filesourcepath); + } elseif (isset($linenum)) + { + $example = $parser->parse($e, $this, $inlinesourceparse, $class, $linenum); + } elseif (isset($class)) + { + $example = $parser->parse($e, $this, $inlinesourceparse, $class); + } else + { + $example = $parser->parse($e, $this, $inlinesourceparse); + } + } + $this->class = $saveclass; + } else + { + $example = $this->postProcess($example); + } + + if ($tutorial) + { + return $example; + } + + if (!isset($this->template_options['desctranslate'])) return $example; + if (!isset($this->template_options['desctranslate']['code'])) return $example; + $example = $this->template_options['desctranslate']['code'] . $example; + if (!isset($this->template_options['desctranslate']['/code'])) return $example; + return $example . $this->template_options['desctranslate']['/code']; + } + + /** + * @param string + */ + function TutorialExample($example) + { + $parse = new phpDocumentor_TutorialHighlightParser; + return $parse->parse($example, $this); + } + + /** + * Used to convert the contents of <
  • > in a docblock + * @param string + * @return string + */ + function ListItem($item) + { + if (!isset($this->template_options['desctranslate'])) return $item; + if (!isset($this->template_options['desctranslate']['li'])) return $item; + $item = $this->template_options['desctranslate']['li'] . $item; + if (!isset($this->template_options['desctranslate']['/li'])) return $item; + return $item . $this->template_options['desctranslate']['/li']; + } + + /** + * Used to convert the contents of <
      > or <
        > in a docblock + * @param string + * @return string + */ + function EncloseList($list,$ordered) + { + $listname = ($ordered ? 'ol' : 'ul'); + if (!isset($this->template_options['desctranslate'])) return $list; + if (!isset($this->template_options['desctranslate'][$listname])) return $list; + $list = $this->template_options['desctranslate'][$listname] . $list; + if (!isset($this->template_options['desctranslate']['/'.$listname])) return $list; + return $list . $this->template_options['desctranslate']['/'.$listname]; + } + + /** + * Used to convert the contents of <
        > in a docblock
        +     * @param string
        +     * @return string
        +     */
        +    function PreserveWhiteSpace($string)
        +    {
        +        if (!isset($this->template_options['desctranslate'])) return $string;
        +        if (!isset($this->template_options['desctranslate']['pre'])) return $string;
        +        $string = $this->template_options['desctranslate']['pre'] . $string;
        +        if (!isset($this->template_options['desctranslate']['/pre'])) return $string;
        +        return $string . $this->template_options['desctranslate']['/pre'];
        +    }
        +
        +    /**
        +     * Used to enclose a paragraph in a docblock
        +     * @param string
        +     * @return string
        +     */
        +    function EncloseParagraph($para)
        +    {
        +        if (!isset($this->template_options['desctranslate'])) return $para;
        +        if (!isset($this->template_options['desctranslate']['p'])) return $para;
        +        $para = $this->template_options['desctranslate']['p'] . $para;
        +        if (!isset($this->template_options['desctranslate']['/p'])) return $para;
        +        return $para . $this->template_options['desctranslate']['/p'];
        +    }
        +
        +    /**
        +     * Used to convert the contents of <> in a docblock
        +     * @param string
        +     * @return string
        +     */
        +    function Bolden($para)
        +    {
        +        if (!isset($this->template_options['desctranslate'])) return $para;
        +        if (!isset($this->template_options['desctranslate']['b'])) return $para;
        +        $para = $this->template_options['desctranslate']['b'] . $para;
        +        if (!isset($this->template_options['desctranslate']['/b'])) return $para;
        +        return $para . $this->template_options['desctranslate']['/b'];
        +    }
        +
        +    /**
        +     * Used to convert the contents of <> in a docblock
        +     * @param string
        +     * @return string
        +     */
        +    function Italicize($para)
        +    {
        +        if (!isset($this->template_options['desctranslate'])) return $para;
        +        if (!isset($this->template_options['desctranslate']['i'])) return $para;
        +        $para = $this->template_options['desctranslate']['i'] . $para;
        +        if (!isset($this->template_options['desctranslate']['/i'])) return $para;
        +        return $para . $this->template_options['desctranslate']['/i'];
        +    }
        +
        +    /**
        +     * Used to convert the contents of <> in a docblock
        +     * @param string
        +     * @return string
        +     */
        +    function Varize($para)
        +    {
        +        if (!isset($this->template_options['desctranslate'])) return $para;
        +        if (!isset($this->template_options['desctranslate']['var'])) return $para;
        +        $para = $this->template_options['desctranslate']['var'] . $para;
        +        if (!isset($this->template_options['desctranslate']['/var'])) return $para;
        +        return $para . $this->template_options['desctranslate']['/var'];
        +    }
        +
        +    /**
        +     * Used to convert the contents of <> in a docblock
        +     * @param string
        +     * @return string
        +     */
        +    function Kbdize($para)
        +    {
        +        if (!isset($this->template_options['desctranslate'])) return $para;
        +        if (!isset($this->template_options['desctranslate']['kbd'])) return $para;
        +        $para = $this->template_options['desctranslate']['kbd'] . $para;
        +        if (!isset($this->template_options['desctranslate']['/kbd'])) return $para;
        +        return $para . $this->template_options['desctranslate']['/kbd'];
        +    }
        +
        +    /**
        +     * Used to convert the contents of <> in a docblock
        +     * @param string
        +     * @return string
        +     */
        +    function Sampize($para)
        +    {
        +        if (!isset($this->template_options['desctranslate'])) return $para;
        +        if (!isset($this->template_options['desctranslate']['samp'])) return $para;
        +        $para = $this->template_options['desctranslate']['samp'] . $para;
        +        if (!isset($this->template_options['desctranslate']['/samp'])) return $para;
        +        return $para . $this->template_options['desctranslate']['/samp'];
        +    }
        +
        +    /**
        +     * Used to convert <
        > in a docblock + * @param string + * @return string + */ + function Br($para) + { + if (!isset($this->template_options['desctranslate'])) return $para; + if (!isset($this->template_options['desctranslate']['br'])) return $para; + $para = $this->template_options['desctranslate']['br'] . $para; + return $para; + } + + /** + * This version does nothing + * + * Perform necessary post-processing of string data. For example, the HTML + * Converters should escape < and > to become < and > + * @return string + */ + function postProcess($text) + { + return $text; + } + + /** + * Creates a table of contents for a {@}toc} inline tag in a tutorial + * + * This function should return a formatted table of contents. By default, it + * does nothing, it is up to the converter to format the TOC + * @abstract + * @return string table of contents formatted for use in the current output format + * @param array format: array(array('tagname' => section, 'link' => returnsee link, 'id' => anchor name, 'title' => from title tag),...) + */ + function formatTutorialTOC($toc) + { + return ''; + } + + /** + * Write out the formatted source code for a php file + * + * This function provides the primary functionality for the + * {@tutorial tags.filesource.pkg} tag. + * @param string full path to the file + * @param string fully highlighted/linked source code of the file + * @abstract + */ + function writeSource($filepath, $source) + { + debug($source); + return; + } + + /** + * Write out the formatted source code for an example php file + * + * This function provides the primary functionality for the + * {@tutorial tags.example.pkg} tag. + * @param string example title + * @param string example filename (no path) + * @param string fully highlighted/linked source code of the file + * @abstract + */ + function writeExample($title, $path, $source) + { + return; + } + + /** Translate the path info into a unique file name for the highlighted + * source code. + * @param string $pathinfo + * @return string + */ + function getFileSourceName($path) + { + global $_phpDocumentor_options; + $pathinfo = $this->proceduralpages->getPathInfo($path, $this); + $pathinfo['source_loc'] = str_replace($_phpDocumentor_options['Program_Root'].'/','',$pathinfo['source_loc']); + $pathinfo['source_loc'] = str_replace('/','_',$pathinfo['source_loc']); + return "fsource_{$pathinfo['package']}_{$pathinfo['subpackage']}_{$pathinfo['source_loc']}"; + } + + /** Return the fixed path to the source-code file folder. + * @param string $base Path is relative to this folder + * @return string + */ + function getFileSourcePath($base) + { + if (substr($base, -1) != PATH_DELIMITER) { + $base .= PATH_DELIMITER; + } + return $base . '__filesource'; + } + + /** Return the path to the current + * @param string $pathinfo + * @return string + */ + function getCurrentPageURL() + { + return '{$srcdir}' . PATH_DELIMITER . $this->page_dir; + } + + /** + * @return string an output-format dependent link to phpxref-style highlighted + * source code + * @abstract + */ + function getSourceLink($path) + { + return ''; + } + + /** + * @return string Link to the current page being parsed. + * Should return {@link $curname} and a converter-specific extension. + * @abstract + */ + function getCurrentPageLink() + { + } + + /** + * Return a line of highlighted source code with formatted line number + * + * If the $path is a full path, then an anchor to the line number will be + * added as well + * @param integer line number + * @param string highlighted source code line + * @param false|string full path to @filesource file this line is a part of, + * if this is a single line from a complete file. + * @return string formatted source code line with line number + */ + function sourceLine($linenumber, $line, $path = false) + { + if ($path) + { + return $this->getSourceAnchor($path, $linenumber) . + $this->Br(sprintf('%-6u',$linenumber).str_replace("\n",'',$line)); + } else + { + return $this->Br(sprintf('%-6u',$linenumber).str_replace("\n",'',$line)); + } + } + + /** + * Determine whether an element's file has generated source code, used for + * linking to line numbers of source. + * + * Wrapper for {@link $sourcePaths} in this version + * @param string full path to the source code file + * @return boolean + */ + function hasSourceCode($path) + { + return isset($this->sourcePaths[$path]); + } + + /** + * Mark a file as having had source code highlighted + * @param string full path of source file + */ + function setSourcePaths($path) + { + $this->sourcePaths[$path] = true; + } + + /** + * Used to translate an XML DocBook entity like ” from a tutorial by + * reading the options.ini file for the template. + * @param string entity name + */ + function TranslateEntity($name) + { + if (!isset($this->template_options['ppage'])) + { + if (!$this->template_options['preservedocbooktags']) + return ''; + else + return '&'.$name.';'; + } + if (isset($this->template_options['ppage']['&'.$name.';'])) + { + return $this->template_options['ppage']['&'.$name.';']; + } else + { + if (!$this->template_options['preservedocbooktags']) + return ''; + else + return '&'.$name.';'; + } + } + + /** + * Used to translate an XML DocBook tag from a tutorial by reading the + * options.ini file for the template. + * @param string tag name + * @param string any attributes Format: array(name => value) + * @param string the tag contents, if any + * @param string the tag contents, if any, unpost-processed + * @return string + */ + function TranslateTag($name,$attr,$cdata,$unconvertedcdata) + { + if (!isset($this->template_options['ppage'])) + { + if (!$this->template_options['preservedocbooktags']) + return $cdata; + else + return '<'.$name.$this->AttrToString($name,$attr,true).'>'.$cdata.''."\n"; + } + // make sure this template transforms the tag into something + if (isset($this->template_options['ppage'][$name])) + { + // test for global attribute transforms like $attr$role = class, changing + // all role="*" attributes to class="*" in html, for example + foreach($attr as $att => $val) + { + if (isset($this->template_options['$attr$'.$att])) + { + $new = ''; + if (!isset($this->template_options['$attr$'.$att]['close'])) + { + $new .= '<'.$this->template_options['$attr$'.$att]['open']; + if (isset($this->template_options['$attr$'.$att]['cdata!'])) + { + if (isset($this->template_options['$attr$'.$att]['separateall'])) + $new .= $this->template_options['$attr$'.$att]['separator']; + else + $new .= ' '; + $new .= $this->template_options['$attr$'.$att]['$'.$att]; + $new .= $this->template_options['$attr$'.$att]['separator']; + if ($this->template_options['$attr$'.$att]['quotevalues']) $val = '"'.$val.'"'; + $new .= $val.'>'; + } else + { + $new .= '>'.$val; + } + $new .= 'template_options['$attr$'.$att]['open'].'>'; + } else + { + $new .= $this->template_options['$attr$'.$att]['open'] . $val . $this->template_options['$attr$'.$att]['close']; + } + unset($attr[$att]); + $cdata = $new . $cdata; + } + } + + if (!isset($this->template_options['ppage']['/'.$name])) + {// if the close tag isn't specified, we put opening and closing tags around it, with translated attributes + if (isset($this->template_options['ppage'][$name.'/'])) + $cdata = '<'.$this->template_options['ppage'][$name].$this->AttrToString($name,$attr).'/>' . $cdata; + else + $cdata = '<'.$this->template_options['ppage'][$name].$this->AttrToString($name,$attr).'>' . $cdata . + 'template_options['ppage'][$name].'>'; + } else + { // if close tag is specified, use the open and close as literal + if ($name == 'programlisting' && isset($attr['role']) && + ($attr['role'] == 'php' || $attr['role'] == 'tutorial' || $attr['role'] == 'html')) + { // highlight PHP source +// var_dump($unconvertedcdata, $cdata);exit; + if ($attr['role'] == 'php') { + $cdata = $this->ProgramExample($unconvertedcdata, true); + } elseif ($attr['role'] == 'tutorial') { + $cdata = $this->TutorialExample($unconvertedcdata); + } elseif ($attr['role'] == 'html') { + $cdata = $unconvertedcdata; + } + } else + {// normal case below + $cdata = $this->template_options['ppage'][$name].$this->AttrToString($name,$attr). $cdata .$this->template_options['ppage']['/'.$name]; + } + } + return $cdata; + } else + { + if ($this->template_options['preservedocbooktags']) + { + return '<'.$name.$this->AttrToString($name,$attr,true).'>' . $cdata . + ''."\n"; + } else + { + return $cdata; + } + } + } + + /** + * Convert the attribute of a Tutorial docbook tag's attribute list + * to a string based on the template options.ini + * @param string tag name + * @param attribute array + * @param boolean if true, returns attrname="value"... + * @return string + */ + function AttrToString($tag,$attr,$unmodified = false) + { + $ret = ''; + if ($unmodified) + { + $ret = ' '; + foreach($attr as $n => $v) + { + $ret .= $n.' = "'.$v.'"'; + } + return $ret; + } + // no_attr tells us to ignore all attributes + if (isset($this->template_options['no_attr'])) return $ret; + // tagname! tells us to ignore all attributes for this tag + if (isset($this->template_options['ppage'][$tag.'!'])) return $ret; + if (count($attr)) $ret = ' '; + // pass 1, check to see if any attributes add together + $same = array(); + foreach($attr as $n => $v) + { + if (isset($this->template_options['ppage'][$tag.'->'.$n])) + { + $same[$this->template_options['ppage'][$tag.'->'.$n]][] = $n; + } + } + foreach($attr as $n => $v) + { + if (isset($this->template_options['ppage'][$tag.'->'.$n])) + { + if (count($same[$this->template_options['ppage'][$tag.'->'.$n]]) == 1) + { // only 1 attribute translated for this one + // this is useful for equivalent value names + if (isset($this->template_options['ppage'][$tag.'->'.$n.'+'.$v])) $v = $this->template_options['ppage'][$tag.'->'.$n.'+'.$v]; + } else + { // more than 1 attribute combines to make the new attribute + $teststrtemp = array(); + foreach($same[$this->template_options['ppage'][$tag.'->'.$n]] as $oldattr) + { + $teststrtemp[] = $oldattr.'+'.$attr[$oldattr]; + } + $teststrs = array(); + $num = count($same[$this->template_options['ppage'][$tag.'->'.$n]]); + for($i=0;$i<$num;$i++) + { + $started = false; + $a = ''; + for($j=$i;!$started || $j != $i;$j = ($j + $i) % $num) + { + if (!empty($a)) $a .= '|'; + $a .= $teststrtemp[$j]; + } + $teststrs[$i] = $a; + } + $done = false; + foreach($teststrs as $test) + { + if ($done) break; + if (isset($this->template_options['ppage'][$tag.'->'.$test])) + { + $done = true; + $v = $this->template_options['ppage'][$tag.'->'.$test]; + } + } + } + $ret .= $this->template_options['ppage'][$tag.'->'.$n].' = "'.$v.'"'; + } else + { + if (!isset($this->template_options['ppage'][$tag.'!'.$n])) + { + if (isset($this->template_options['ppage']['$attr$'.$n])) + $ret .= $this->template_options['ppage']['$attr$'.$n].' = "'.$v.'"'; + else + $ret .= $n.' = "'.$v.'"'; + } + } + } + return $ret; + } + + /** + * Convert the title of a Tutorial docbook tag section + * to a string based on the template options.ini + * @param string tag name + * @param array + * @param string title text + * @param string + * @return string + */ + function ConvertTitle($tag,$attr,$title,$cdata) + { + if (!isset($this->template_options[$tag.'_title'])) return array($attr,$title.$cdata); + if (isset($this->template_options[$tag.'_title']['tag_attr'])) + { + $attr[$this->template_options[$tag.'_title']['tag_attr']] = urlencode($cdata); + $cdata = ''; + } elseif(isset($this->template_options[$tag.'_title']['cdata_start'])) + { + $cdata = $this->template_options[$tag.'_title']['open'] . $title . + $this->template_options[$tag.'_title']['close'] . $cdata; + } else $cdata = $title.$cdata; + return array($attr,$cdata); + } + + /** + * Return a converter-specific id to distinguish tutorials and their + * sections + * + * Used by {@}id} + * @return string + */ + function getTutorialId($package,$subpackage,$tutorial,$id) + { + return $package.$subpackage.$tutorial.$id; + } + + /** + * Create the {@link $elements, $pkg_elements} and {@link $links} arrays + * @access private + * @todo version 2.0 - faulty package_output logic should be removed + * + * in this version, if the parent file isn't in the package, all + * the procedural elements are simply shunted to another package! + */ + function _createPkgElements(&$pages) + { + if (empty($this->elements)) + { + $this->elements = array(); + $this->pkg_elements = array(); + $this->links = array(); + phpDocumentor_out('Building indexes...'); + flush(); + foreach($pages as $j => $flub) + { + $this->package = $pages[$j]->parent->package; + $this->subpackage = $pages[$j]->parent->subpackage; + $this->class = false; + $this->curfile = $pages[$j]->parent->getFile(); + $this->curname = $this->getPageName($pages[$j]->parent); + $this->curpath = $pages[$j]->parent->getPath(); + $use = true; + if ($this->package_output) + { + if (in_array($this->package,$this->package_output)) + { + $this->addElement($pages[$j]->parent,$pages[$j]); + } else + { + if (count($pages[$j]->classelements)) + { + list(,$pages[$j]->parent->package) = each($this->package_output); + reset($this->package_output); + $pages[$j]->parent->subpackage = ''; + $this->addElement($pages[$j]->parent,$pages[$j]); + } else + { + unset($pages[$j]); + continue; + } + } + } else + { + $this->addElement($pages[$j]->parent,$pages[$j]); + } + if ($use) + for($i=0; $ielements); $i++) + { + $pages[$j]->elements[$i]->docblock->package = $this->package; + $pages[$j]->elements[$i]->docblock->subpackage = $this->subpackage; + $this->proceduralpages->replaceElement($pages[$j]->elements[$i]); + $this->addElement($pages[$j]->elements[$i]); + } + for($i=0; $iclasselements); $i++) + { + if ($this->class) + { + if ($pages[$j]->classelements[$i]->type == 'class') + { + if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue; + $this->package = $pages[$j]->classelements[$i]->docblock->package; + if ($this->package_output) if (!in_array($this->package,$this->package_output)) continue; + $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage; + $this->class = $pages[$j]->classelements[$i]->name; + } else + { + if ($this->killclass) continue; + // force all contained elements to have parent package/subpackage + $pages[$j]->classelements[$i]->docblock->package = $this->package; + $pages[$j]->classelements[$i]->docblock->subpackage = $this->subpackage; + } + } + if ($pages[$j]->classelements[$i]->type == 'class') + { + if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue; + $this->package = $pages[$j]->classelements[$i]->docblock->package; + if ($this->package_output) if (!in_array($this->package,$this->package_output)) continue; + $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage; + $this->class = $pages[$j]->classelements[$i]->name; + } + if (!$this->killclass) $this->addElement($pages[$j]->classelements[$i]); + } + } + phpDocumentor_out("done\n"); + flush(); + } + $this->sortIndexes(); + $this->sortTodos(); + if ($this->sort_page_contents_by_type) $this->sortPageContentsByElementType($pages); + } + + /** + * Process the {@link $tutorials} array + * + * Using the tutorialname.ext.ini files, this method sets up tutorial + * hierarchy. There is some minimal error checking to make sure that no + * tutorial links to itself, even two levels deep as in tute->next->tute. + * + * If all tests pass, it creates the hierarchy + * @uses generateTutorialOrder() + * @uses _setupTutorialTree() + * @access private + */ + function _processTutorials() + { + $parents = $all = array(); + foreach($this->tutorials as $package => $els) + { + if ($this->package_output) + { + if (!in_array($package,$this->package_output)) + { + unset($this->tutorials[$package]); + continue; + } + } + if (!isset($this->pkg_elements[$package])) + { + unset($this->tutorials[$package]); + continue; + } + foreach($els as $subpackage => $els2) + { + foreach($els2 as $type => $tutorials) + { + foreach($tutorials as $tutorial) + { + if ($tutorial->ini) + { + if (isset($tutorial->ini['Linked Tutorials'])) + { + foreach($tutorial->ini['Linked Tutorials'] as $child) + { + $sub = (empty($tutorial->subpackage) ? '' : $tutorial->subpackage . '/'); + $kid = $tutorial->package . '/' . $sub . $child . '.' . $tutorial->tutorial_type; + // parent includes self as a linked tutorial? + $kidlink = $this->getTutorialLink($kid,false,false,array($tutorial->package)); + if (is_object($kidlink) && $this->returnSee($kidlink) == $tutorial->getLink($this)) + { // bad! + addErrorDie(PDERROR_TUTORIAL_IS_OWN_CHILD,$tutorial->name,$tutorial->name.'.ini'); + } + } + $parents[] = $tutorial; + } + } + $all[$package][$subpackage][$type][] = $tutorial; + } + } + } + } + // loop error-checking, use this to eliminate possibility of accidentally linking to a parent as a child + $testlinks = array(); + foreach($parents as $parent) + { + $testlinks[$parent->name]['links'][] = $parent->getLink($this); + $testlinks[$parent->name]['name'][$parent->getLink($this)] = $parent->name; + } + // generate the order of tutorials, and link them together + foreach($parents as $parent) + { + foreach($parent->ini['Linked Tutorials'] as $child) + { + $sub = (empty($parent->subpackage) ? '' : $parent->subpackage . '/'); + $kid = $parent->package . '/' . $sub . $child . '.' . $parent->tutorial_type; + // child tutorials must be in the same package AND subpackage + // AND have the same extension as the parent, makes things clearer for both ends + if (in_array($this->returnSee($this->getTutorialLink($kid,false,false,array($parent->package))),$testlinks[$parent->name]['links'])) + addErrorDie(PDERROR_TUTORIAL_IS_OWN_GRANDPA,$testlinks[$parent->name][$this->returnSee($this->getTutorialLink($kid,false,false,array($parent->package)))],$kid->name,$testlinks[$parent->name][$this->returnSee($this->getTutorialLink($kid,false,false,array($parent->package)))],$kid->name.'.ini'); + if ($this->returnSee($this->getTutorialLink($kid,false,false,array($parent->package))) == $kid) + { + addWarning(PDERROR_CHILD_TUTORIAL_NOT_FOUND, $child . '.' . $parent->tutorial_type, $parent->name .'.ini',$parent->package, $parent->subpackage); + } + } + } + $new = $tree = $roots = array(); + // build a list of all 'root' tutorials (tutorials without parents). + foreach($parents as $i => $parent) + { + if (! $parent->isChildOf($parents)) { + $roots[] = $parent; + } + } + $parents = $roots; + // add the parents and all child tutorials in order to the list of tutorials to process + foreach($parents as $parent) + { + $this->generateTutorialOrder($parent,$all,$new); + } + if (count($all)) + { + // add the leftover tutorials + foreach($all as $package => $els) + { + foreach($els as $subpackage => $els2) + { + foreach($els2 as $type => $tutorials) + { + foreach($tutorials as $tutorial) + { + $new[$package][$subpackage][$type][] = $tutorial; + } + } + } + } + } + // remove the old, unprocessed tutorials, and set it up with the next code + $this->tutorials = array(); + // reset integrity of the tutorial list + $prev = false; + uksort($new, 'tutorialcmp'); +// debug($this->vardump_tree($new));exit; + foreach($new as $package => $els) + { + foreach($els as $subpackage => $els2) + { + foreach($els2 as $type => $tutorials) + { + foreach($tutorials as $tutorial) + { + if ($prev) + { + $this->tutorials[$prevpackage][$prevsubpackage][$prevtype][$prevname]->setNext($tutorial,$this); + $tutorial->setPrev($prev,$this); + } + $this->tutorials[$package][$subpackage][$type][$tutorial->name] = $tutorial; + $prev = $tutorial->getLink($this,true); + $prevpackage = $package; + $prevsubpackage = $subpackage; + $prevtype = $type; + $prevname = $tutorial->name; + } + } + } + } + $this->tutorial_tree = $this->_setupTutorialTree(); + return $new; + } + + /** + * called by {@link phpDocumentor_IntermediateParser::Convert()} to traverse + * the array of pages and their elements, converting them to the output format + * + * The walk() method should be flexible enough such that it never needs + * modification. walk() sets up all of the indexes, and sorts everything in + * logical alphabetical order. It then passes each element individually to + * {@link Convert()}, which then passes to the Convert*() methods. A child + * Converter need not override any of these unless special functionality must + * be added. see {@tutorial Converters/template.vars.cls} for details. + * {@internal + * walk() first creates all of the indexes {@link $elements, $pkg_elements} + * and the left indexes specified by {@link $leftindexes}, + * and then sorts them by calling {@link sortIndexes()}. + * + * Next, it converts all README/CHANGELOG/INSTALL-style files, using + * {@link Convert_RIC}. + * + * After this, it + * passes all package-level docs to Convert(). Then, it calls the index + * sorting functions {@link formatPkgIndex(), formatIndex()} and + * {@link formatLeftIndex()}. + * + * Finally, it converts each procedural page in alphabetical order. This + * stage passes elements from the physical file to Convert() in alphabetical + * order. First, procedural page elements {@link parserDefine, parserInclude} + * {@link parserGlobal}, and {@link parserFunction} are passed to Convert(). + * + * Then, class elements are passed in this order: {@link parserClass}, then + * all of the {@link parserVar}s in the class and all of the + * {@link parserMethod}s in the class. Classes are in alphabetical order, + * and both vars and methods are in alphabetical order. + * + * Finally, {@link ConvertErrorLog()} is called and the data walk is complete.}} + * @param array Format: array(fullpath => {@link parserData} structure with full {@link parserData::$elements} + * and {@link parserData::$class_elements}. + * @param array Format: array({@link parserPackagePage} 1, {@link parserPackagePage} 2,...) + * @uses Converter::_createPkgElements() sets up {@link $elements} and + * {@link $pkg_elements} array, as well as {@link $links} + */ + function walk(&$pages,&$package_pages) + { + if (empty($pages)) + { + die("ERROR: nothing parsed"); + } + $this->_createPkgElements($pages); + if (count($this->ric)) + { + phpDocumentor_out("Converting README/INSTALL/CHANGELOG contents...\n"); + flush(); + foreach($this->ric as $name => $contents) + { + phpDocumentor_out("$name..."); + flush(); + $this->Convert_RIC($name,$contents); + } + phpDocumentor_out("\ndone\n"); + flush(); + } + foreach($package_pages as $i => $perp) + { + if ($this->package_output) + { + if (!in_array($package_pages[$i]->package,$this->package_output)) continue; + } + phpDocumentor_out('Converting package page for package '.$package_pages[$i]->package.'... '); + flush(); + $this->package = $package_pages[$i]->package; + $this->subpackage = ''; + $this->class = false; + $this->Convert($package_pages[$i]); + phpDocumentor_out("done\n"); + flush(); + } + phpDocumentor_out("Converting tutorials/extended docs\n"); + flush(); + // get tutorials into the order they will display, and set next/prev links + $new = $this->_processTutorials(); + foreach($this->tutorials as $package => $els) + { + foreach($els as $subpackage => $els2) + { + foreach($els2 as $type => $tutorials) + { + foreach($tutorials as $tutorial) + { + switch ($type) + { + case 'pkg' : + $a = ''; + if ($tutorial->ini) + $a .= 'Top-level '; + if (!empty($tutorial->subpackage)) + $a .= 'Sub-'; + $ptext = "Converting ${a}Package-level tutorial ".$tutorial->name.'...'; + break; + case 'cls' : + $a = ''; + if ($tutorial->ini) + $a .= 'Top-level '; + $ptext = "Converting ${a}Class-level tutorial " . $tutorial->name ." and associating..."; + $link = Converter::getClassLink(str_replace('.cls','',$tutorial->name), $tutorial->package); + if (is_object($link)) + { + if ($this->sort_absolutely_everything) + { + $addend = 'unsuccessful '; + if (isset($this->package_elements[$tutorial->package][$tutorial->subpackage]['class'][$link->name])) + { + $this->package_elements[$tutorial->package][$tutorial->subpackage]['class'][$link->name][0]->addTutorial($tutorial,$this); + $addend = 'success '; + } + } else + { + $addend = 'unsuccessful '; + if (!isset($this->classes->killclass[str_replace('.cls','',$tutorial->name)]) && !isset($this->classes->killclass[str_replace('.cls','',$tutorial->name)][$tutorial->path])) + { + foreach($pages as $j => $inf) + { + foreach($inf->classelements as $i => $class) + { + if ($class->type == 'class' && $class->name == str_replace('.cls','',$tutorial->name) && $class->path == $link->path) + { + $pages[$j]->classelements[$i]->addTutorial($tutorial,$this); + $addend = 'success '; + } + } + } + } + } + $ptext .= $addend; + } else $ptext .= "unsuccessful "; + break; + case 'proc' : + $a = ''; + if ($tutorial->ini) + $a .= 'Top-level '; + $ptext = "Converting ${a}Procedural-level tutorial ".$tutorial->name." and associating..."; + $link = Converter::getPageLink(str_replace('.proc','',$tutorial->name), $tutorial->package); + if (is_object($link)) + { + $addend = 'unsuccessful '; + if ($this->sort_absolutely_everything) + { + if (isset($this->package_elements[$tutorial->package][$tutorial->subpackage]['page'][$link->path])) + { + $this->package_elements[$tutorial->package][$tutorial->subpackage]['page'][$link->path][0]->addTutorial($tutorial,$this); + $addend = "success "; + } + } else + { + foreach($pages as $j => $info) + { + if ($j == $link->path) + { + $pages[$j]->addTutorial($tutorial,$this); + $addend = "success "; + } + } + } + $ptext .= $addend; + } else $ptext .= "unsuccessful "; + break; + } + phpDocumentor_out($ptext); + flush(); + $this->package = $tutorial->package; + $this->subpackage = $tutorial->subpackage; + $this->Convert($tutorial); + phpDocumentor_out("done\n"); + flush(); + } + } + } + } + phpDocumentor_out("Formatting Package Indexes..."); + flush(); + $this->formatPkgIndex(); + phpDocumentor_out("done\n"); + flush(); + phpDocumentor_out("Formatting Index..."); + flush(); + $this->formatIndex(); + phpDocumentor_out("done\n\n"); + flush(); + phpDocumentor_out("Formatting Left Quick Index..."); + flush(); + $this->formatLeftIndex(); + phpDocumentor_out("done\n\n"); + flush(); + if ($this->sort_absolutely_everything) return $this->walk_everything(); + foreach($pages as $j => $flub) + { + phpDocumentor_out('Converting '.$pages[$j]->parent->getPath()); + flush(); + $this->package = $pages[$j]->parent->package; + $this->subpackage = $pages[$j]->parent->subpackage; + $this->class = false; + $this->curfile = $pages[$j]->parent->getFile(); + $this->curname = $this->getPageName($pages[$j]->parent); + $this->curpath = $pages[$j]->parent->getPath(); + $use = true; + if ($this->package_output) + { + if (in_array($this->package,$this->package_output)) + { + $this->Convert($pages[$j]); + } else + { + $use = false; + } + } else + { + $this->Convert($pages[$j]); + } + phpDocumentor_out(" Procedural Page Elements..."); + flush(); + if ($use) + for($i=0; $ielements); $i++) + { + $a = $pages[$j]->elements[$i]->docblock->getKeyword('access'); + if (is_object($a)) $a = $a->getString(); + if (!$this->parseprivate && ($a == 'private')) + continue; +// phpDocumentor_out(" ".$pages[$j]->elements[$i]->name."\n"); + $pages[$j]->elements[$i]->docblock->package = $this->package; + $pages[$j]->elements[$i]->docblock->subpackage = $this->subpackage; + $this->Convert($pages[$j]->elements[$i]); + } + phpDocumentor_out(" Classes..."); + $this->class = false; + flush(); + for($i=0; $iclasselements); $i++) + { + if ($this->class) + { + if ($pages[$j]->classelements[$i]->type == 'class') + { + if (!$this->killclass) $this->endClass(); + $this->killclass = false; + if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue; + $this->package = $pages[$j]->classelements[$i]->docblock->package; + if ($this->package_output) if (!in_array($this->package,$this->package_output)) continue; + $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage; + $this->class = $pages[$j]->classelements[$i]->name; + } else + { + $a = $pages[$j]->classelements[$i]->docblock->getKeyword('access'); + if (is_object($a)) $a = $a->getString(); + if (!$this->parseprivate && ($a == 'private')) + continue; + if ($this->killclass) continue; + // force all contained elements to have parent package/subpackage + $pages[$j]->classelements[$i]->docblock->package = $this->package; + $pages[$j]->classelements[$i]->docblock->subpackage = $this->subpackage; + } + } + if ($pages[$j]->classelements[$i]->type == 'class') + { + $this->killclass = false; + if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue; + $this->package = $pages[$j]->classelements[$i]->docblock->package; + if ($this->package_output) if (!in_array($this->package,$this->package_output)) continue; + $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage; + $this->class = $pages[$j]->classelements[$i]->name; + } + if ($this->killclass) continue; +// phpDocumentor_out(" ".$pages[$j]->classelements[$i]->name."\n"); + $this->Convert($pages[$j]->classelements[$i]); + } + if (count($pages[$j]->classelements) && !$this->killclass) $this->endClass(); + phpDocumentor_out(" done\n"); + flush(); + $this->endPage(); + } + phpDocumentor_out("\nConverting @todo List..."); + flush(); + if (count($this->todoList)) + { + $this->ConvertTodoList(); + } + phpDocumentor_out("done\n"); + flush(); + phpDocumentor_out("\nConverting Error Log..."); + flush(); + $this->ConvertErrorLog(); + phpDocumentor_out("done\n"); + flush(); + } + + + /** + * Get a tree structure representing the hierarchy of tutorials + * + * Returns an array in format: + *
        +     * array('tutorial' => {@link parserTutorial},
        +     *       'kids' => array( // child tutorials
        +     *                   array('tutorial' => child {@link parserTutorial},
        +     *                         'kids' => array(...)
        +     *                        )
        +     *                      )
        +     *      )
        +     * 
        + * @param parserTutorial|array + * @tutorial tutorials.pkg + * @return array + */ + function getTutorialTree($tutorial) + { + if (is_object($tutorial)) + { + $path = $tutorial->package . '/' . $tutorial->subpackage . '/' . $tutorial->name; + if (isset($this->tutorial_tree[$path])) + $tutorial = $this->tutorial_tree[$path]; + else + return false; + } + $tree = array(); + if (isset($tutorial['tutorial'])) + { + $tree['tutorial'] = $tutorial['tutorial']; + if (isset($tutorial['child'])) + { + foreach($tutorial['child'] as $a => $b) + { + $btut = $b['tutorial']; + $res['tutorial'] = $this->tutorials[$btut->package][$btut->subpackage][$btut->tutorial_type][$btut->name]; + if (isset($b['child'])) + { + $tempres = Converter::getTutorialTree($b); + $res['kids'] = $tempres['kids']; + } + $tree['kids'][] = $res; + } + } + } + return $tree; + } + + /** + * Remove tutorials one by one from $all, and transfer them into $new in the + * order they should be parsed + * @param parserTutorial + * @param array + * @param array + * @access private + */ + function generateTutorialOrder($parent,&$all,&$new) + { + // remove from the list of tutorials to process + foreach($all[$parent->package][$parent->subpackage][$parent->tutorial_type] as $ind => $t) + { + if ($t->name == $parent->name) { + unset($all[$parent->package][$parent->subpackage][$parent->tutorial_type][$ind]); + } + } + // add to the new ordered list of tutorials + $x = &$new[$parent->package][$parent->subpackage][$parent->tutorial_type]; + if (!is_object($x[count($x) - 1]) || $x[count($x) - 1]->name != $parent->name) + { // only add if the parent isn't also a child + $new[$parent->package][$parent->subpackage][$parent->tutorial_type][] = $parent; + // add a new branch to the tree + } + // process all child tutorials, and insert them in order +// debug("processing parent ".$parent->name); + if ($parent->ini) + { + foreach($parent->ini['Linked Tutorials'] as $child) + { + $sub = (empty($parent->subpackage) ? '' : $parent->subpackage . '/'); + $kid = $parent->package . '/' . $sub . $child . '.' . $parent->tutorial_type; + $_klink = $this->getTutorialLink($kid,false,false,array($parent->package)); + if (is_object($_klink)) { + $klink = $this->returnSee($_klink); + } else { + $klink = false; + } + // remove the child from the list of remaining tutorials + foreach($all[$parent->package][$parent->subpackage][$parent->tutorial_type] as $ind => $tute) + { + if ($klink && $tute->getLink($this) == $klink) + { + // set up parent, next and prev links + $tute->setParent($parent, $this); + // remove the child from the list of tutorials to process + foreach($all[$parent->package][$parent->subpackage][$parent->tutorial_type] as $ind => $t) + { + if ($t->name == $tute->name) + unset($all[$parent->package][$parent->subpackage][$parent->tutorial_type][$ind]); + } + // add to the new ordered list of tutorials + $new[$parent->package][$parent->subpackage][$parent->tutorial_type][] = $tute; + if ($tute->ini) + { + // add all the child's child tutorials to the list + $this->generateTutorialOrder($tute,$all,$new); + } + } + } + } + } + return; + } + + /** Returns the path to this tutorial as a string + * @param parserTutorial $pkg + * @param parserTutorial $subpkg + * @param parserTutorial $namepkg + * @return string */ + function _tutorial_path($pkg, $subpkg = 0, $namepkg = 0) + { + if (! $subpkg) + $subpkg = $pkg; + if (! $namepkg) + $namepkg = $pkg; + return $pkg->package.'/'.$subpkg->subpackage.'/'.$namepkg->name; + } + + + /** + * Creates a tree structure of tutorials + * + * Format: + *
        +     * array('package/subpackage/tutorial1.ext' =>
        +     *          array('tutorial' => {@link parserTutorial},
        +     *                'child'    =>
        +     *                    array('package/subpackage/child1tutorial.ext' => ...,
        +     *                          'package/subpackage/child2tutorial.ext' => ...,
        +     *                          ...
        +     *                         )
        +     *       'package/subpackage/tutorial2.ext' => ...,
        +     *       ...
        +     *       )
        +     * 
        + * @return array the tutorial tree + * @access private + */ + function _setupTutorialTree($parent = false) + { + if (! isset($this->processed_tutorials)) + $this->processed_tutorials = array(); + $tree = array(); + if (!$parent) + { + foreach($this->tutorials as $package => $s) + { + foreach($s as $subpackage => $t) + { + foreach($t as $type => $n) + { + foreach($n as $name => $tutorial) + { + if (!$tutorial->parent) + { + $child_path = $this->_tutorial_path($tutorial,$tutorial,$tutorial); + if (! isset($this->processed_tutorials[$child_path])) + { + $this->processed_tutorials[$child_path] = $tutorial; + //debug("parent ".$tutorial->name); + $ret = $this->_setupTutorialTree($tutorial); + if (!count($tree)) + $tree = $ret; + else + $tree = array_merge($tree,$ret); + } + } + } + } + } + } + return $tree; + } + $parent_path = $this->_tutorial_path($parent); + $tree[$parent_path]['tutorial'] = $parent; + // process all child tutorials, and insert them in order + if ($parent->ini) + { + foreach($parent->ini['Linked Tutorials'] as $child) + { + if (isset($this->tutorials[$parent->package][$parent->subpackage][$parent->tutorial_type][$child . '.' . $parent->tutorial_type])) + // remove the child from the list of remaining tutorials + $tute = $this->tutorials[$parent->package][$parent->subpackage][$parent->tutorial_type][$child . '.' . $parent->tutorial_type]; + else + $tute = false; + + if ($tute) + { + $child_path = $this->_tutorial_path($parent,$parent,$tute); + if (! isset($this->processed_tutorials[$child_path])) + { + $this->processed_tutorials[$child_path] = $tute; + if ($tute->name == $child . '.' . $parent->tutorial_type) + { +// echo "Adding [$child_path] to [$parent_path]
        "; + $tree[$parent_path]['child'][$this->_tutorial_path($parent,$parent,$tute)]['tutorial'] = $tute; + if ($tute->ini) + { + // add all the child's child tutorials to the list + if (!isset($tree[$parent_path]['child'])) + $tree[$parent_path]['child'] = $this->_setupTutorialTree($tute); + else + $tree[$parent_path]['child'] = array_merge($tree[$parent_path]['child'],$this->_setupTutorialTree($tute)); + } + } + } + } + } + } + return $tree; + } + + /** + * Debugging function for dumping {@link $tutorial_tree} + * @return string + */ + function vardump_tree($tree,$indent='') + { + if (phpDocumentor_get_class($tree) == 'parsertutorial') return $tree->name.' extends '.($tree->parent? $tree->parent->name : 'nothing'); + $a = ''; + foreach($tree as $ind => $stuff) + { + $x = $this->vardump_tree($stuff,"$indent "); + $a .= $indent.'['.$ind." => \n ".$indent.$x."]\n"; + } + return substr($a,0,strlen($a) - 1); + } + + /** + * @access private + */ + function sort_package_elements($a,$b) + { + if (($a->type == $b->type) && (isset($a->isConstructor) && $a->isConstructor)) return -1; + if (($a->type == $b->type) && (isset($b->isConstructor) && $b->isConstructor)) return 1; + if ($a->type == $b->type) return strnatcasecmp($a->name,$b->name); + if ($a->type == 'class') return -1; + if ($b->type == 'class') return 1; + if ($a->type == 'const') return -1; + if ($b->type == 'const') return 1; + if ($a->type == 'var') return -1; + if ($b->type == 'var') return 1; + if ($a->type == 'page') return -1; + if ($b->type == 'page') return 1; + if ($a->type == 'include') return -1; + if ($b->type == 'include') return 1; + if ($a->type == 'define') return -1; + if ($b->type == 'define') return 1; + if ($a->type == 'global') return -1; + if ($b->type == 'global') return 1; + if ($a->type == 'function') return -1; + if ($b->type == 'function') return 1; + } + + /** + * @access private + */ + function defpackagesort($a,$b) + { + if ($a == $GLOBALS['phpDocumentor_DefaultPackageName']) return -1; + if ($b == $GLOBALS['phpDocumentor_DefaultPackageName']) return 0; + return strnatcasecmp($a,$b); + } + + /** + * @access private + */ + function Pc_sort($a,$b) + { + return strnatcasecmp(key($a),key($b)); + } + + /** + * walk over elements by package rather than page + * + * This method is designed for converters like the PDF converter that need + * everything passed in alphabetical order by package/subpackage and by + * procedural and then class information + * @see PDFdefaultConverter + * @see walk() + */ + function walk_everything() + { + global $hooser; + $hooser = false; + uksort($this->package_elements,array($this,'defpackagesort')); + foreach($this->package_elements as $package => $r) + { + if ($this->package_output) + { + if (!in_array($this->package,$this->package_output)) + { + unset($this->package_elements[$package]); + continue; + } + } + uksort($this->package_elements[$package],'strnatcasecmp'); + } + foreach($this->package_elements as $package => $r) + { + foreach($this->package_elements[$package] as $subpackage => $r) + { + if (isset($r['page'])) + { + uksort($r['page'],'strnatcasecmp'); + foreach($r['page'] as $page => $oo) + { + usort($this->package_elements[$package][$subpackage]['page'][$page],array($this,'sort_package_elements')); + } + } + if (isset($r['class'])) + { + uksort($r['class'],'strnatcasecmp'); + foreach($r['class'] as $page => $oo) + { + usort($r['class'][$page],array($this,'sort_package_elements')); + } + } + $this->package_elements[$package][$subpackage] = $r; + } + } + foreach($this->package_elements as $package => $s) + { + $notyet = false; + foreach($s as $subpackage => $r) + { + $this->package = $package; + $this->subpackage = $subpackage; + if (isset($r['page'])) + { + $this->class = false; + foreach($r['page'] as $page => $elements) + { + if (is_array($elements)) + { + foreach($elements as $element) + { + if ($element->type == 'page') + { + phpDocumentor_out('Converting '.$element->parent->getPath()); + flush(); + $this->curfile = $element->parent->getFile(); + $this->curname = $this->getPageName($element->parent); + $this->curpath = $element->parent->getPath(); + $notyet = true; + } else + { + // force all contained elements to have parent package/subpackage + $element->docblock->package = $this->package; + $element->docblock->subpackage = $this->subpackage; + $a = $element->docblock->getKeyword('access'); + if (is_object($a)) $a = $a->getString(); + if (!$this->parseprivate && ($a == 'private')) + continue; + } + if ($notyet) + { + phpDocumentor_out(" Procedural Page Elements..."); + flush(); + $notyet = false; + } + $this->Convert($element); + } + } + $this->endPage(); + phpDocumentor_out("done\n"); + flush(); + } + } + $start_classes = true; + if (isset($r['class'])) + { + foreach($r['class'] as $class => $elements) + { + foreach($elements as $element) + { + if ($element->type == 'class') + { + if (!$start_classes) + { + if (count($elements) && !$this->killclass) $this->endClass(); + phpDocumentor_out("done\n"); + flush(); + } + $start_classes = false; + $this->class = $element->getName(); + $this->killclass = false; + if ($this->checkKillClass($element->getName(),$element->getPath())) continue; + if (!$this->killclass) + { + phpDocumentor_out('Converting '.$this->class."..."); + flush(); + $notyet = true; + } + } else + { + if ($notyet) + { + phpDocumentor_out("Variables/methods/Class constants...\n"); + flush(); + $notyet = false; + } + $a = $element->docblock->getKeyword('access'); + if (is_object($a)) $a = $a->getString(); + if (!$this->parseprivate && ($a == 'private')) + continue; + if ($this->killclass) continue; + // force all contained elements to have parent package/subpackage + $element->docblock->package = $this->package; + $element->docblock->subpackage = $this->subpackage; + } + if ($this->killclass) continue; + $this->Convert($element); + } + } + if (count($elements) && !$this->killclass) $this->endClass(); + phpDocumentor_out("done\n"); + flush(); + } // if isset($r['class']) + } // foreach($s + } // foreach($this->package_elements) + phpDocumentor_out("\nConverting @todo List..."); + flush(); + if (count($this->todoList)) + { + $this->ConvertTodoList(); + } + phpDocumentor_out("done\n"); + flush(); + phpDocumentor_out("\nConverting Error Log..."); + flush(); + $this->ConvertErrorLog(); + phpDocumentor_out("done\n"); + flush(); + } + + /** + * Convert the phpDocumentor parsing/conversion error log + * @abstract + */ + function ConvertErrorLog() + { + } + + /** + * Convert the list of all @todo tags + * @abstract + */ + function ConvertTodoList() + { + } + + /** + * Sorts the @todo list - do not override or modify this function + * @access private + * @uses _sortTodos passed to {@link usort()} to sort the todo list + */ + function sortTodos() + { + phpDocumentor_out("\nSorting @todo list..."); + flush(); + foreach($this->todoList as $package => $r) + usort($this->todoList[$package],array($this, '_sortTodos')); + phpDocumentor_out("done\n"); + } + + /** @access private */ + function _sortTodos($a, $b) + { + return strnatcasecmp($a[0]->name, $b[0]->name); + } + + /** + * Sorts all indexes - do not override or modify this function + * @uses $leftindex based on the value of leftindex, sorts link arrays + * @uses $class_elements sorts with {@link compareLink} + * @uses $page_elements sorts with {@link compareLink} + * @uses $define_elements sorts with {@link compareLink} + * @uses $global_elements sorts with {@link compareLink} + * @uses $function_elements sorts with {@link compareLink} + * @uses $elements sorts with {@link elementCmp} + * @uses $pkg_elements sorts with {@link elementCmp} after sorting by + * package/subpackage alphabetically + * @access private + */ + function sortIndexes() + { + phpDocumentor_out("\nSorting Indexes..."); + flush(); + uksort($this->elements,'strnatcasecmp'); + if ($this->leftindex['classes']) + { + foreach($this->class_elements as $package => $o1) + { + foreach($o1 as $subpackage => $links) + { + usort($this->class_elements[$package][$subpackage],array($this,'compareLink')); + } + } + } + if ($this->leftindex['pages']) + { + foreach($this->page_elements as $package => $o1) + { + uksort($this->page_elements[$package],'strnatcasecmp'); + foreach($o1 as $subpackage => $links) + { + usort($this->page_elements[$package][$subpackage],array($this,'compareLink')); + } + } + } + if ($this->leftindex['defines']) + { + foreach($this->define_elements as $package => $o1) + { + uksort($this->define_elements[$package],'strnatcasecmp'); + foreach($o1 as $subpackage => $links) + { + usort($this->define_elements[$package][$subpackage],array($this,'compareLink')); + } + } + } + if ($this->leftindex['globals']) + { + foreach($this->global_elements as $package => $o1) + { + uksort($this->global_elements[$package],'strnatcasecmp'); + foreach($o1 as $subpackage => $links) + { + usort($this->global_elements[$package][$subpackage],array($this,'compareLink')); + } + } + } + if ($this->leftindex['functions']) + { + foreach($this->function_elements as $package => $o1) + { + uksort($this->function_elements[$package],'strnatcasecmp'); + foreach($o1 as $subpackage => $links) + { + usort($this->function_elements[$package][$subpackage],array($this,'compareLink')); + } + } + } + foreach($this->elements as $letter => $nothuing) + { + uasort($this->elements[$letter],array($this,"elementCmp")); + } + foreach($this->pkg_elements as $package => $els) + { + uksort($this->pkg_elements[$package],'strnatcasecmp'); + foreach($this->pkg_elements[$package] as $subpackage => $els) + { + if (empty($els)) continue; + uksort($this->pkg_elements[$package][$subpackage],'strnatcasecmp'); + foreach($els as $letter => $yuh) + { + usort($this->pkg_elements[$package][$subpackage][$letter],array($this,"elementCmp")); + } + } + } + phpDocumentor_out("done\n"); + flush(); + } + + /** + * sorts {@link $page_contents} by element type as well as alphabetically + * @see $sort_page_contents_by_element_type + */ + function sortPageContentsByElementType(&$pages) + { + foreach($this->page_contents as $package => $els) + { + foreach($this->page_contents[$package] as $subpackage => $els) + { + if (empty($els)) continue; + foreach($this->page_contents[$package][$subpackage] as $path => $stuff) + { + if (!count($pages[$path]->elements)) continue; + usort($pages[$path]->elements,array($this,'eltypecmp')); + usort($this->page_contents[$package][$subpackage][$path],array($this,'eltypecmp')); + if (isset($this->page_contents[$package][$subpackage][$path][0])) + $this->page_contents[$package][$subpackage][$path]['###main'] = $this->page_contents[$package][$subpackage][$path][0]; + unset($this->page_contents[$package][$subpackage][$path][0]); + } + } + } + } + + /** + * @access private + * @see Converter::sortIndexes() + */ + function compareLink($a, $b) + { + return strnatcasecmp($a->name,$b->name); + } + + /** + * @access private + * @see Converter::sortPageContentsByElementType() + */ + function eltypecmp($a, $b) + { + if ($a->type == 'page') return -1; + if ($b->type == 'page') return 1; + return strnatcasecmp($a->type.$a->name,$b->type.$b->name); + } + + /** + * does a nat case sort on the specified second level value of the array + * + * @param mixed $a + * @param mixed $b + * @return int + * @access private + */ + function elementCmp ($a, $b) + { + return strnatcasecmp($a->getName(), $b->getName()); + } + + /** + * Used to stop conversion of @ignored or private @access classes + * @uses $killclass sets killclass based on the value of {@link Classes::$killclass} + * and {@link $package_output} + * @access private + */ + function checkKillClass($class, $path) + { + $this->killclass = false; + if (isset($this->classes->killclass[$class]) && isset($this->classes->killclass[$class][$path])) $this->killclass = true; + if ($this->package_output) + { + $a = $this->classes->getClass($class, $path); + if (!in_array($a->docblock->package,$this->package_output)) $this->killclass = true; + } + if (PHPDOCUMENTOR_DEBUG && $this->killclass) debug("$class $path killed"); + return $this->killclass; + } + + /** + * @param abstractLink descendant of abstractLink + * @param array|parserTag list of @todos|@todo tag + * @access private + */ + function addTodoLink($link, $todos) + { + $this->todoList[$link->package][] = array($link, $todos); + } + + /** + * Adds all elements to the {@link $elements, $pkg_elements, $links}, + * {@link $linkswithfile} and left indexes - Do not modify or override + * @access private + * @param parserBase any documentable element descendant of parserBase + * except parserTutorial + * @param false|parserPage only used to add a {@link parserPage} if the + * $element passed is a parserPage + * @staticvar string path of current page, used for {@link $page_contents} setup + */ + function addElement(&$element,$pageel=false) + { + static $curpath = ''; + if ($this->package_output) + { + if (!in_array($this->package, $this->package_output)) return; + } + if ($pageel && phpDocumentor_get_class($pageel) == 'parserdata') + { + if (isset($pageel->docblock) && phpDocumentor_get_class($pageel->docblock) == 'parserdocblock') + { + $a = $pageel->docblock->getKeyword('todo'); + if ($a) + { + $this->addTodoLink($this->addLink($element),$a); + } + } + } + if (isset($element->docblock)) + { + $a = $element->docblock->getKeyword('access'); + if (is_object($a)) $a = $a->getString(); + if (!$this->parseprivate && ($a == 'private')) + return; + $a = $element->docblock->getKeyword('todo'); + if ($a) + { + $this->addTodoLink($this->addLink($element),$a); + } + } + $i = 0; + switch($element->type) + { + case 'page' : + if ($this->sort_absolutely_everything) + { + $this->package_elements[$element->package][$element->subpackage]['page'][$element->getPath()][] = $pageel; + } + $link = $this->addLink($element); + $curpath = $element->getPath(); + if ($this->leftindex['pages']) + $this->page_elements[$element->package][$element->subpackage][] = $link; + $this->page_contents[$element->package][$element->subpackage][$curpath]['###main'] = $link; + break; + case 'class' : + if ($this->sort_absolutely_everything) + { + $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][] = $element; + } + $link = $this->addLink($element); + if ($this->leftindex['classes']) + $this->class_elements[$element->docblock->package][$element->docblock->subpackage][] = $link; + $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class]['###main'] = $link; + break; + case 'include' : + if ($this->sort_absolutely_everything) + { + $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][] = $element; + } + $link = $this->addLink($element); + break; + case 'define' : + if ($this->sort_absolutely_everything) + { + $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][] = $element; + } + $link = $this->addLink($element); + if ($this->leftindex['defines']) + $this->define_elements[$element->docblock->package][$element->docblock->subpackage][] = $link; + $this->page_contents[$element->docblock->package][$element->docblock->subpackage][$curpath][] = $link; + break; + case 'global' : + if ($this->sort_absolutely_everything) + { + $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][] = $element; + } + $link = $this->addLink($element); + $i++; + if ($this->leftindex['globals']) + $this->global_elements[$element->docblock->package][$element->docblock->subpackage][] = $link; + $this->page_contents[$element->docblock->package][$element->docblock->subpackage][$curpath][] = $link; + break; + case 'var' : + if ($this->sort_absolutely_everything) + { + $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][] = $element; + } + $link = $this->addLink($element); + $i++; + $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class][] = $link; + break; + case 'const' : + if ($this->sort_absolutely_everything) + { + $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][] = $element; + } + $link = $this->addLink($element); + $i++; + $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class][] = $link; + break; + case 'method' : + if ($this->sort_absolutely_everything) + { + $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][] = $element; + } + $link = $this->addLink($element); + $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class][] = $link; + break; + case 'function' : + if ($this->sort_absolutely_everything) + { + $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][] = $element; + } + $link = $this->addLink($element); + if ($this->leftindex['functions']) + $this->function_elements[$element->docblock->package][$element->docblock->subpackage][] = $link; + $this->page_contents[$element->docblock->package][$element->docblock->subpackage][$curpath][] = $link; + break; + default : + break; + } + if ($element->getType() != 'include') + { + if ($element->getType() == 'var' || $element->getType() == 'method'|| $element->getType() == 'const') + { + $this->links[$this->package][$this->subpackage][$element->getType()][$element->class][$element->getName()] = $link; + $this->linkswithfile[$this->package][$this->subpackage][$element->getType()][$element->getPath()][$element->class][$element->getName()] = $link; + } else + { + if ($element->type == 'page') + { + $this->links[$this->package][$this->subpackage][$element->getType()][$element->getFile()] = $link; + $this->linkswithfile[$this->package][$this->subpackage][$element->getType()][$element->getPath()][$element->getFile()] = $link; + } else + { + $this->links[$this->package][$this->subpackage][$element->getType()][$element->getName()] = $link; + $this->linkswithfile[$this->package][$this->subpackage][$element->getType()][$element->getPath()][$element->getName()] = $link; + } + } + } + if ($element->type == 'page') + { + $this->elements[substr(strtolower($element->getFile()),$i,1)][] = $element; + $this->pkg_elements[$this->package][$this->subpackage][substr(strtolower($element->getFile()),$i,1)][] = $element; + } else + { + $this->elements[substr(strtolower($element->getName()),$i,1)][] = $element; + $this->pkg_elements[$this->package][$this->subpackage][substr(strtolower($element->getName()),$i,1)][] = $element; + } + } + + /** + * returns an abstract link to element. Do not modify or override + * + * This method should only be called in process of Conversion, unless + * $element is a parserPage, or $page is set to true, and $element is + * not a parserPage + * @return abstractLink abstractLink descendant + * @access private + * @param parserElement element to add a new link (descended from + * {@link abstractLink})to the {@link $links} array + * @param string classname for elements that are class-based (this may be + * deprecated in the future, as the classname + * should be contained within the element. if $element is a + * page, this parameter is a package name + * @param string subpackage name for page elements + */ + function addLink(&$element,$page = false) + { + if ($page) + { + // create a fake parserPage to extract the fileAlias for this link + $fakepage = new parserPage; + $fakepage->setPath($element->getPath()); + $fakepage->setFile(basename($element->getPath())); + $this->curname = $this->getPageName($fakepage); + } + switch($element->type) + { + case 'function': + $x = new functionLink; + $x->addLink($element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category); + return $x; + break; + case 'define': + $x = new defineLink; + $x->addLink($element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category); + return $x; + break; + case 'global': + $x = new globalLink; + $x->addLink($element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category); + return $x; + break; + case 'class': + $x = new classLink; + $x->addLink($element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category); + return $x; + break; + case 'method': + $x = new methodLink; + $x->addLink($this->class, $element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category); + return $x; + break; + case 'var': + $x = new varLink; + $x->addLink($this->class, $element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category); + return $x; + break; + case 'const': + $x = new constLink; + $x->addLink($this->class, $element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category); + return $x; + break; + case 'page': + $x = new pageLink; + $x->addLink($element->getPath(),$this->getPageName($element),$element->file,$element->package, $element->subpackage, $element->category); + return $x; + break; + } + } + + /** + * Return a tree of all classes that extend this class + * + * The data structure returned is designed for a non-recursive algorithm, + * and is somewhat complex. + * In most cases, the array returned is: + * + *
        +     * array('#root' =>
        +     *         array('link' => {@link classLink} to $class,
        +     *               'parent' => false,
        +     *               'children' => array(array('class' => 'childclass1',
        +     *                                         'package' => 'child1package'),
        +     *                                    array('class' => 'childclass2',
        +     *                                         'package' => 'child2package'),...
        +     *                                  )
        +     *               ),
        +     *       'child1package#childclass1' =>
        +     *         array('link' => {@link classLink} to childclass1,
        +     *               'parent' => '#root',
        +     *               'children' => array(array('class' => 'kidclass',
        +     *                                         'package' => 'kidpackage'),...
        +     *                                  )
        +     *              ),
        +     *       'kidpackage#kidclass' =>
        +     *         array('link' => {@link classLink} to kidclass,
        +     *               'parent' => 'child1package#childclass1',
        +     *               'children' => array() // no children
        +     *              ),
        +     *      ....
        +     *      )
        +     *
        + * + * To describe this format using language, every class in the tree has an + * entry in the first level of the array. The index for all child + * classes that extend the root class is childpackage#childclassname. + * Each entry in the array has 3 elements: link, parent, and children. + *
          + *
        • link - a {@link classLink} to the current class
        • + *
        • parent - a {@link classLink} to the class's parent, or false (except for one special case described below)
        • + *
        • children - an array of arrays, each entry has a 'class' and 'package' index to the child class, + * used to find the entry in the big array
        • + *
        + * + * special cases are when the #root class has a parent in another package, + * or when the #root class extends a class not found + * by phpDocumentor. In the first case, parent will be a + * classLink to the parent class. In the second, parent will be the + * extends clause, as in: + * + * class X extends Y + * { + * ... + * } + * + * in this case, the #root entry will be array('link' => classLink to X, 'parent' => 'Y', children => array(...)) + * + * The fastest way to design a method to process the array returned + * is to copy HTMLframesConverter::getRootTree() into + * your converter and to modify the html to whatever output format you are going to use + * @see HTMLframesConverter::getRootTree() + * @param string class name + * @param string + * @param string + * @return array Format: see docs + */ + function getSortedClassTreeFromClass($class,$package,$subpackage) + { + $my_tree = array(); + $root = $this->classes->getClassByPackage($class,$package); + if (!$root) return false; + $class_children = $this->classes->getDefiniteChildren($class,$root->curfile); + if (!$class_children) + { + // special case: parent class is found, but is not part of this package, class has no children + if (is_array($root->parent)) + { + $x = $root->getParent($this); + if ($x->docblock->package != $package) + { + $v = Converter::getClassLink($root->getName(),$package,$root->getPath()); + return array('#root' => array('link' => $v,'parent' => Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath()), 'children' => array())); + } + } else + { // class has normal situation, no children + if (is_string($root->getParent($this))) + return array('#root' => array('link' => Converter::getClassLink($root->getName(),$package,$root->getPath()), 'parent' => $root->getExtends(),'children' => array())); + else + return array('#root' => array('link' => Converter::getClassLink($root->getName(),$package,$root->getPath()), 'parent' => false, 'children' => array())); + } + } + // special case: parent class is found, but is not part of this package, class has children + if (is_array($root->parent)) + { + $x = $root->getParent($this); + if ($x->docblock->package != $package) + { + $v = Converter::getClassLink($root->getName(),$package,$root->getPath()); + $my_tree = array('#root' => array('link' => $v, 'parent' => Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath()), 'children' => array())); + } else + { + } + } else + $my_tree = array('#root' => array('link' => Converter::getClassLink($root->getName(),$package,$root->getPath()), 'parent' => false, 'children' => array())); + // location of tree walker + $cur = '#root'; + $lastcur = array(array(false,0)); + $childpos = 0; + if (isset($class_children)) + { + do + { + if (!$class_children) + { + list($cur, $childpos) = array_pop($lastcur); + if (isset($my_tree[$cur]['children'][$childpos + 1])) + { + array_push($lastcur, array($cur, $childpos + 1)); + $par = $cur; + $cur = $my_tree[$cur]['children'][$childpos + 1]; + $x = $this->classes->getClassByPackage($cur['class'],$cur['package']); + $childpos = 0; + $cur = $cur['package'] . '#' . $cur['class']; + $my_tree[$cur]['link'] = Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath()); + $my_tree[$cur]['parent'] = $par; + $my_tree[$cur]['children'] = array(); + $class_children = $this->classes->getDefiniteChildren($x->getName(), $x->curfile); + continue; + } else + { + $class_children = false; + continue; + } + } + foreach($class_children as $chileclass => $chilefile) + { + $ch = $this->classes->getClass($chileclass,$chilefile); + $my_tree[$cur]['children'][] = array('class' => $ch->getName(), 'package' => $ch->docblock->package); + } + usort($my_tree[$cur]['children'],'rootcmp'); + if (isset($my_tree[$cur]['children'][$childpos])) + { + array_push($lastcur, array($cur, $childpos)); + $par = $cur; + $cur = $my_tree[$cur]['children'][$childpos]; + $x = $this->classes->getClassByPackage($cur['class'],$cur['package']); + $cur = $cur['package'] . '#' . $cur['class']; + $my_tree[$cur]['link'] = Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath()); + $my_tree[$cur]['parent'] = $par; + $my_tree[$cur]['children'] = array(); + $childpos = 0; + $class_children = $this->classes->getDefiniteChildren($x->getName(), $x->curfile); + } else + { + list($cur, $childpos) = array_pop($lastcur); + } + } while ($cur); + } + return $my_tree; + } + + /** + * do not override + * @return bool true if a link to this class exists in package $package and subpackage $subpackage + * @param string $expr class name + * @param string $package package to search in + * @param string $subpackage subpackage to search in + * @access private + */ + function isLinkedClass($expr,$package,$subpackage,$file=false) + { + if ($file) + return isset($this->linkswithfile[$package][$subpackage]['class'][$file][$expr]); + return isset($this->links[$package][$subpackage]['class'][$expr]); + } + + /** + * do not override + * @return bool true if a link to this function exists in package $package and subpackage $subpackage + * @param string $expr function name + * @param string $package package to search in + * @param string $subpackage subpackage to search in + * @access private + */ + function isLinkedFunction($expr,$package,$subpackage,$file=false) + { + if ($file) + return isset($this->linkswithfile[$package][$subpackage]['function'][$file][$expr]); + return isset($this->links[$package][$subpackage]['function'][$expr]); + } + + /** + * do not override + * @return bool true if a link to this define exists in package $package and subpackage $subpackage + * @param string $expr define name + * @param string $package package to search in + * @param string $subpackage subpackage to search in + * @access private + */ + function isLinkedDefine($expr,$package,$subpackage,$file=false) + { + if ($file) + return isset($this->linkswithfile[$package][$subpackage]['define'][$file][$expr]); + return isset($this->links[$package][$subpackage]['define'][$expr]); + } + + /** + * do not override + * @return bool true if a link to this define exists in package $package and subpackage $subpackage + * @param string $expr define name + * @param string $package package to search in + * @param string $subpackage subpackage to search in + * @access private + */ + function isLinkedGlobal($expr,$package,$subpackage,$file=false) + { + if ($file) + return isset($this->linkswithfile[$package][$subpackage]['global'][$file][$expr]); + return isset($this->links[$package][$subpackage]['global'][$expr]); + } + + /** + * do not override + * @return bool true if a link to this procedural page exists in package $package and subpackage $subpackage + * @param string $expr procedural page name + * @param string $package package to search in + * @param string $subpackage subpackage to search in + * @access private + */ + function isLinkedPage($expr,$package,$subpackage,$path=false) + { + if ($path) + return isset($this->linkswithfile[$package][$subpackage]['page'][$path][$expr]); + return isset($this->links[$package][$subpackage]['page'][$expr]); + } + + /** + * do not override + * @return bool true if a link to this method exists in package $package, subpackage $subpackage and class $class + * @param string $expr method name + * @param string $class class name + * @param string $package package to search in + * @param string $subpackage subpackage to search in + * @access private + */ + function isLinkedMethod($expr,$package,$subpackage,$class,$file=false) + { + if ($file) + return isset($this->linkswithfile[$package][$subpackage]['method'][$file][$class][$expr]); + return isset($this->links[$package][$subpackage]['method'][$class][$expr]); + } + + /** + * do not override + * @return bool true if a link to this method exists in package $package, subpackage $subpackage and class $class + * @param string $expr var name + * @param string $class class name + * @param string $package package to search in + * @param string $subpackage subpackage to search in + * @access private + */ + function isLinkedVar($expr,$package,$subpackage,$class,$file=false) + { + if ($file) + return isset($this->linkswithfile[$package][$subpackage]['var'][$file][$class][$expr]); + return isset($this->links[$package][$subpackage]['var'][$class][$expr]); + } + + /** + * do not override + * @return bool true if a link to this method exists in package $package, subpackage $subpackage and class $class + * @param string $expr constant name + * @param string $class class name + * @param string $package package to search in + * @param string $subpackage subpackage to search in + * @access private + */ + function isLinkedConst($expr,$package,$subpackage,$class,$file=false) + { + if ($file) + return isset($this->linkswithfile[$package][$subpackage]['const'][$file][$class][$expr]); + return isset($this->links[$package][$subpackage]['const'][$class][$expr]); + } + + /** + * return false or a {@link classLink} to $expr + * @param string $expr class name + * @param string $package package name + * @return mixed returns a {@link classLink} or false if the element is not found in package $package + * @see classLink + */ + function getClassLink($expr,$package,$file=false, $text = false) + { + if (!isset($this->links[$package])) return false; + foreach($this->links[$package] as $subpackage => $notused) + { + if ($this->isLinkedClass($expr,$package,$subpackage,$file)) + { + if ($file) + { + return $this->linkswithfile[$package][$subpackage]['class'][$file][$expr]; + } + return $this->links[$package][$subpackage]['class'][$expr]; + } + } + return false; + } + + /** + * return false or a {@link functionLink} to $expr + * @param string $expr function name + * @param string $package package name + * @return mixed returns a {@link functionLink} or false if the element is not found in package $package + * @see functionLink + */ + function getFunctionLink($expr,$package,$file=false, $text = false) + { + if (!isset($this->links[$package])) return false; + foreach($this->links[$package] as $subpackage => $notused) + { + if ($this->isLinkedFunction($expr,$package,$subpackage,$file)) + { + if ($file) + { + return $this->linkswithfile[$package][$subpackage]['function'][$file][$expr]; + } + return $this->links[$package][$subpackage]['function'][$expr]; + } + } + return false; + } + + /** + * return false or a {@link defineLink} to $expr + * @param string $expr constant name + * @param string $package package name + * @return mixed returns a {@link defineLink} or false if the element is not found in package $package + * @see defineLink + */ + function getDefineLink($expr,$package,$file=false, $text = false) + { + if (!isset($this->links[$package])) return false; + foreach($this->links[$package] as $subpackage => $notused) + { + if ($this->isLinkedDefine($expr,$package,$subpackage,$file)) + { + if ($file) + { + return $this->linkswithfile[$package][$subpackage]['define'][$file][$expr]; + } + return $this->links[$package][$subpackage]['define'][$expr]; + } + } + return false; + } + + /** + * return false or a {@link globalLink} to $expr + * @param string $expr global variable name (with leading $) + * @param string $package package name + * @return mixed returns a {@link defineLink} or false if the element is not found in package $package + * @see defineLink + */ + function getGlobalLink($expr,$package,$file=false, $text = false) + { + if (!isset($this->links[$package])) return false; + foreach($this->links[$package] as $subpackage => $notused) + { + if ($this->isLinkedGlobal($expr,$package,$subpackage,$file)) + { + if ($file) + { + return $this->linkswithfile[$package][$subpackage]['global'][$file][$expr]; + } + return $this->links[$package][$subpackage]['global'][$expr]; + } + } + return false; + } + + /** + * return false or a {@link pageLink} to $expr + * @param string $expr procedural page name + * @param string $package package name + * @return mixed returns a {@link pageLink} or false if the element is not found in package $package + * @see pageLink + */ + function getPageLink($expr,$package,$path = false, $text = false, $packages = false) + { + if (!isset($this->links[$package])) return false; + foreach($this->links[$package] as $subpackage => $notused) + { + if ($this->isLinkedPage($expr,$package,$subpackage,$path)) + { + if ($path) + { + return $this->linkswithfile[$package][$subpackage]['page'][$path][$expr]; + } + return $this->links[$package][$subpackage]['page'][$expr]; + } + } + return false; + } + + /** + * return false or a {@link methodLink} to $expr in $class + * @param string $expr method name + * @param string $class class name + * @param string $package package name + * @return mixed returns a {@link methodLink} or false if the element is not found in package $package, class $class + * @see methodLink + */ + function getMethodLink($expr,$class,$package,$file=false, $text = false) + { + $expr = trim($expr); + $class = trim($class); + if (!isset($this->links[$package])) return false; + foreach($this->links[$package] as $subpackage => $notused) + { + if ($this->isLinkedMethod($expr,$package,$subpackage,$class,$file)) + { + if ($file) + { + return $this->linkswithfile[$package][$subpackage]['method'][$file][$class][$expr]; + } + return $this->links[$package][$subpackage]['method'][$class][$expr]; + } + } + return false; + } + + /** + * return false or a {@link varLink} to $expr in $class + * @param string $expr var name + * @param string $class class name + * @param string $package package name + * @return mixed returns a {@link varLink} or false if the element is not found in package $package, class $class + * @see varLink + */ + function getVarLink($expr,$class,$package,$file=false, $text = false) + { + $expr = trim($expr); + $class = trim($class); + if (!isset($this->links[$package])) return false; + foreach($this->links[$package] as $subpackage => $notused) + { + if ($this->isLinkedVar($expr,$package,$subpackage,$class,$file)) + { + if ($file) + { + return $this->linkswithfile[$package][$subpackage]['var'][$file][$class][$expr]; + } + return $this->links[$package][$subpackage]['var'][$class][$expr]; + } + } + return false; + } + + /** + * return false or a {@link constLink} to $expr in $class + * @param string $expr constant name + * @param string $class class name + * @param string $package package name + * @return mixed returns a {@link varLink} or false if the element is not found in package $package, class $class + * @see constLink + */ + function getConstLink($expr,$class,$package,$file=false, $text = false) + { + $expr = trim($expr); + $class = trim($class); + if (!isset($this->links[$package])) return false; + foreach($this->links[$package] as $subpackage => $notused) + { + if ($this->isLinkedConst($expr,$package,$subpackage,$class,$file)) + { + if ($file) + { + return $this->linkswithfile[$package][$subpackage]['const'][$file][$class][$expr]; + } + return $this->links[$package][$subpackage]['const'][$class][$expr]; + } + } + return false; + } + + /** + * The meat of the @tutorial tag and inline {@}tutorial} tag + * + * Take a string and return an abstract link to the tutorial it represents. + * Since tutorial naming literally works like the underlying filesystem, the + * way to reference the tutorial is similar. Tutorials are located in a + * subdirectory of any directory parsed, which is named 'tutorials/' (we + * try to make things simple when we can :). They are further organized by + * package and subpackage as: + * + * tutorials/package/subpackage + * + * and the files are named *.cls, *.pkg, or *.proc, and so a link to a tutorial + * named file.cls can be referenced (depending on context) as any of: + * + * + * * @tutorial package/subpackage/file.cls + * * @tutorial package/file.cls + * * @tutorial file.cls + * + * + * The first case will only be needed if file.cls exists in both the current + * package, in anotherpackage/file.cls and in anotherpackage/subpackage/file.cls + * and you wish to reference the one in anotherpackage/subpackage. + * The second case is only needed if you wish to reference file.cls in another + * package and it is unique in that package. the third will link to the first + * file.cls it finds using this search method: + * + *
          + *
        1. current package/subpackage
        2. + *
        3. all other subpackages of current package
        4. + *
        5. parent package, if this package has classes that extend classes in + * another package
        6. + *
        7. all other packages
        8. + *
        + * @return tutorialLink|string returns either a link, or the original text, if not found + * @param string the original expression + * @param string package to look in first + * @param string subpackage to look in first + * @param array array of package names to search in if not found in parent packages. + * This is used to limit the search, phpDocumentor automatically searches + * all packages + * @since 1.2 + */ + function getTutorialLink($expr, $package = false, $subpackage = false, $packages = false) + { + // is $expr a comma-delimited list? + if (strpos($expr,',')) + { + $a = explode(',',$expr); + $b = array(); + for($i=0;$ipackage; + if (!$subpackage) $subpackage = $this->subpackage; + if (!isset($this->all_packages[$package])) return $expr; + elseif (isset($packages[$package])) unset($packages[$package]); + $ext = pathinfo($expr, PATHINFO_EXTENSION); + if (isset($this->tutorials[$package][$subpackage][$ext][$expr])) + { + $a = $this->tutorials[$package][$subpackage][$ext][$expr]; + $link = new tutorialLink; + $link->addLink($subsection,$a->path,$a->name,$a->package,$a->subpackage,$a->getTitle($this,$subsection)); + return $link; + } + do + { + if (!is_array($packages)) + { + $packages = $this->all_packages; + if (isset($packages[$package])) unset($packages[$package]); + } + if (isset($this->tutorials[$package])) + { + if (isset($this->tutorials[$package][$subpackage][$ext][$expr])) + { + $a = $this->tutorials[$package][$subpackage][$ext][$expr]; + $link = new tutorialLink; + $link->addLink($subsection,$a->path,$a->name,$a->package,$a->subpackage,$a->getTitle($this)); + return $link; + } else + { + foreach($this->tutorials[$package] as $subpackage => $stuff) + { + if (isset($stuff[$ext][$expr])) + { + $a = $stuff[$ext][$expr]; + $link = new tutorialLink; + $link->addLink($subsection,$a->path,$a->name,$a->package,$a->subpackage,$a->getTitle($this)); + return $link; + } + } + } + } + // try other packages + // look in parent package first, if found + if (isset($this->package_parents[$package])) + { + $p1 = $package; + $package = $this->package_parents[$package]; + } else + { + // no parent package, so start with the first one that's left + list($package,) = @each($packages); + } + if ($package) + { + if (isset($packages[$package])) unset($packages[$package]); + } + } while (count($packages) || $package); + addWarning(PDERROR_TUTORIAL_NOT_FOUND,$expr); + return $expr; + } + + /** + * The meat of the @see tag and inline {@}link} tag + * + * $expr is a string with many allowable formats: + *
          + *
        1. proceduralpagename.ext
        2. + *
        3. constant_name
        4. + *
        5. classname::function()
        6. + *
        7. classname::constantname
        8. (new 1.2.4) + *
        9. classname::$variablename
        10. + *
        11. classname
        12. + *
        13. function functionname()
        14. + *
        15. global $globalvarname
        16. + *
        17. packagename#expr where expr is any of the above
        18. + *
        + * + * New in version 1.1, you can explicitly specify a package to link to that + * is different from the current package. Use the # operator + * to specify a new package, as in tests#bug-540368.php (which should appear + * as a link like: "{@link tests#bug-540368.php}"). This + * example links to the procedural page bug-540368.php in package + * tests. Also, the "function" operator is now used to specifically + * link to a function instead of a method in the current class. + * + * + * class myclass + * { + * // from inside the class definition, use "function conflict()" to refer to procedural function "conflict()" + * function conflict() + * { + * } + * } + * + * function conflict() + * { + * } + * + * + * If classname:: is not present, and the see tag is in a documentation + * block within a class, then the function uses the classname to + * search for $expr as a function or variable within classname, or any of its parent classes. + * given an $expr without '$', '::' or '()' getLink first searches for + * classes, procedural pages, constants, global variables, and then searches for + * methods and variables within the default class, and finally for any function + * + * @param string $expr expression to search for a link + * @param string $package package to start searching in + * @param array $packages list of all packages to search in + * @return mixed getLink returns a descendant of {@link abstractLink} if it finds a link, otherwise it returns a string + * @see getPageLink(), getDefineLink(), getVarLink(), getFunctionLink(), getClassLink() + * @see pageLink, functionLink, defineLink, classLink, methodLink, varLink + */ + function &getLink($expr, $package = false, $packages = false) + { + // is $expr a comma-delimited list? + if (strpos($expr,',')) + { + $a = explode(',',$expr); + $b = array(); + for($i=0;$i_getLink($expr, $package, $packages); + return $a; + } + + /** + * @access private + */ + function &_getLink($expr, $package = false, $packages = false) + { + if (!$package) $package = $this->package; + // + if (!isset($this->all_packages[$package])) return $expr; + elseif (isset($packages[$package])) unset($packages[$package]); + $links = &$this->links; + $class = $this->class; + if (strpos($expr,'function ') === 0) + { // asking for a function, not a method + if ($test = Converter::getFunctionLink(str_replace('function ','',str_replace('()','',$expr)), $package)) return $test; + else return $expr; + } + if (strpos($expr,'global ') === 0) + { // asking for a global variable + if ($test = Converter::getGlobalLink(str_replace('global ','',$expr), $package)) return $test; + else return $expr; + } + if (strpos($expr,'object ') === 0) + { // asking for a class + if ($test = Converter::getClassLink(str_replace('object ','',$expr), $package)) return $test; + else return $expr; + } + if (strpos($expr,'constant ') === 0) + { // asking for a class + if ($test = Converter::getDefineLink(str_replace('constant ','',$expr), $package)) return $test; + else return $expr; + } + // are we in a class? + if ($class) + { + // is $expr simply a word? see if it is the class + if (trim($expr) == $class) + { + if ($test = Converter::getClassLink(trim(str_replace('object ','',$expr)),$package)) return $test; + } + // if not, check to see if it is a method or variable of this class tree + if (!strpos($expr,'::')) + { + // if get is neither get() nor $get, assume get is a function, add () to make get() + if (strpos($expr,'$') !== 0 && !strpos($expr,'()')) //$get = $get.'()'; + { + if ($a = $this->getLinkMethod($expr,$class,$package)) return $a; + if ($a = $this->getLinkConst($expr,$class,$package)) return $a; + if ($a = $this->getLinkVar('$'.$expr,$class,$package)) return $a; + } + if (strpos($expr,'()')) if ($a = $this->getLinkMethod($expr,$class,$package)) return $a; + if (is_numeric(strpos($expr,'$'))) if ($a = $this->getLinkVar($expr,$class,$package)) return $a; + } + } + if ($test = Converter::getClassLink(trim(str_replace('object ','',$expr)),$package)) return $test; + if ($test = Converter::getPageLink(trim($expr),$package)) return $test; + if ($test = Converter::getDefineLink(trim($expr),$package)) return $test; + if ($test = Converter::getGlobalLink(trim($expr),$package)) return $test; +// if (strpos($expr,'.')) + // package specified + + if (!is_array($packages)) + { + $packages = $this->all_packages; + } + do + { + if (isset($packages[$package])) unset($packages[$package]); + if ($test = Converter::getClassLink(str_replace('object ','',$expr),$package)) return $test; + if ($test = Converter::getPageLink($expr,$package)) return $test; + if ($test = Converter::getDefineLink($expr,$package)) return $test; + if ($test = Converter::getGlobalLink($expr,$package)) return $test; + // is $expr in class::method() or class::$variable format? + if (strpos($expr,'function ') === 0) + { // asking for a function, not a method + if ($test = Converter::getFunctionLink(str_replace('function','',str_replace('()','',$expr)), $package)) return $test; + else return $expr; + } + $test = $this->_getDoubleColon($expr, $package, $packages, $class, $links); + if (!is_string($test)) return $test; + if (strpos($test, 'parent::') === 0) return $test; + // $expr does not have :: + if (is_numeric(@strpos('$',$expr))) + { + // default to current class, whose name is contained in $this->render->parent + if ($test = Converter::getVarLink($expr, $class, $package)) return $test; + } + // $expr is a function? (non-method) + if (@strpos($expr,'()')) + { + // otherwise, see if it is a method + if ($class) + { + if ($test = Converter::getMethodLink(str_replace('()','',$expr), $class, $package)) return $test; + } + // extract the function name, use it to retrieve the file that the function is in + // $page = $this->func_page[str_replace('function ','',str_replace('()','',$expr))]; + // return the link + if ($test = Converter::getFunctionLink(str_replace('function ','',str_replace('()','',$expr)), $package)) return $test; + } + // $expr is just a word. First, test to see if it is a function of the current package + if ($test = Converter::getFunctionLink(str_replace('function ','',str_replace('()','',$expr)), $package)) return $test; + // try other packages + // look in parent package first, if found + if (isset($this->package_parents[$package]) && in_array($this->package_parents[$package], $packages)) + { + $p1 = $package; + $package = $this->package_parents[$package]; + if ($package) + { + if (isset($packages[$package])) unset($packages[$package]); + } + continue; + } + // no parent package, so start with the first one that's left + $package = @array_shift(@array_keys($packages)); + if ($package && isset($packages[$package])) + { + unset($packages[$package]); + } + } while (count($packages) || $package); + $funcs = get_defined_functions(); + // feature 564991, link to php manual + if (in_array(str_replace(array('(',')'),array('',''),$expr),$funcs['internal'])) + { + return 'http://www.php.net/'.str_replace(array('(',')'),array('',''),$expr); + } + // no links found + return $expr; + } + + /** + * Split up getLink to make it easier to debug + * @access private + */ + function _getDoubleColon(&$expr, &$package, &$packages, $class, $links) + { + if (@strpos($expr,'::')) + { + $class_method = explode('::',$expr); + if ($class_method[0] == 'parent') + { + // can only have parent in the same package as the class! subtle bug + $package = $this->package; + $packages = array(); + $cl = $this->classes->getClassByPackage($class,$package); + if (!$cl) + { // this is possible if an example file has parent::method() + return $expr; + } + $par = $cl->getParent($this); + $phpparent = false; + if (is_object($par)) + { + $package = $par->docblock->package; + $phpparent = $par->getName(); + } else + { + addWarning(PDERROR_CLASS_PARENT_NOT_FOUND,$class,$package,$class_method[1]); + return $expr; + } + if ($phpparent) $class_method[0] = $phpparent; + } + if (strpos($class_method[1],'()')) + { + // strip everything but the function name, return a link + if ($test = Converter::getMethodLink(str_replace('()','',$class_method[1]), $class_method[0], $package)) return $test; + } + if ($test = Converter::getVarLink($class_method[1], $class_method[0], $package)) return $test; + if ($test = Converter::getConstLink($class_method[1], $class_method[0], $package)) return $test; + } + return $expr; + } + + /** + * cycle through parent classes to retrieve a link to a method + * do not use or override, used by getLink + * @access private + */ + function &getLinkMethod($expr, $class, $package) + { + $links = &$this->links; + do + { + // is $expr in class::method() or class::$variable format? + if (@strpos($expr,'::')) + { + $class_method = explode('::',$expr); + if ($class_method[0] == 'parent') + { + $cl = $this->classes->getClassByPackage($class,$package); + $par = $cl->getParent($this); + $phpparent = false; + if (is_object($par)) + { + $package = $par->docblock->package; + $phpparent = $par->getName(); + } else addWarning(PDERROR_CLASSPARENT_NOTFOUND,$class,$package,$class_method[1]); + if ($phpparent) $class_method[0] = $phpparent; + } else + { + $cl = $this->classes->getClassByPackage($class,$package); + } + if (strpos($class_method[1],'()')) + { + // strip everything but the function name, return a link + if ($test = Converter::getMethodLink(str_replace('function ','',str_replace('()','',$class_method[1])), $class_method[0], $package)) return $test; + } + } + if ($test = Converter::getMethodLink(str_replace('()','',$expr), $class, $package)) return $test; + $cl = $this->classes->getClassByPackage($class,$package); + if ($cl) + { + $par = $cl->getParent($this); + if (is_object($par)) + { + $package = $par->docblock->package; + $class = $par->getName(); + } else $class = $par; + } else $class = false; + } while ($class); + // no links found + return false; + } + + /** + * cycle through parent classes to retrieve a link to a var + * do not use or override, used by getLink + * @access private + */ + function &getLinkVar($expr, $class, $package) + { + $links = &$this->links; + do + { + // is $expr in class::method() or class::$variable format? + if (@strpos($expr,'::')) + { + $class_method = explode('::',$expr); + if ($class_method[0] == 'parent') + { + $cl = $this->classes->getClassByPackage($class,$package); + $phpparent = false; + $par = $cl->getParent($this); + if (is_object($par)) + { + $package = $par->docblock->package; + $phpparent = $par->getName(); + } else addWarning(PDERROR_CLASSPARENT_NOTFOUND,$class,$package,$class_method[1]); + if ($phpparent) $class_method[0] = $phpparent; + } else + { + $cl = $this->classes->getClassByPackage($class,$package); + } + if ($test = Converter::getVarLink($class_method[1], $class_method[0], $package)) return $test; + if ($test = Converter::getVarLink('$'.$class_method[1], $class_method[0], $package)) return $test; + } + if ($test = Converter::getVarLink($expr, $class, $package)) return $test; + if ($test = Converter::getVarLink('$'.$expr, $class, $package)) return $test; + $cl = $this->classes->getClassByPackage($class,$package); + if ($cl) + { + $par = $cl->getParent($this); + if (is_object($par)) + { + $package = $par->docblock->package; + $class = $par->getName(); + } else $class = $par; + } else $class = false; + } while ($class); + // no links found + $class = false; + return $class; + } + + /** + * cycle through parent classes to retrieve a link to a class constant + * do not use or override, used by getLink + * @access private + * @since 1.2.4 + */ + function &getLinkConst($expr, $class, $package) + { + $links = &$this->links; + do + { + // is $expr in class::method() or class::$variable format? + if (@strpos($expr,'::')) + { + $class_method = explode('::',$expr); + if ($class_method[0] == 'parent') + { + $cl = $this->classes->getClassByPackage($class,$package); + $phpparent = false; + $par = $cl->getParent($this); + if (is_object($par)) + { + $package = $par->docblock->package; + $phpparent = $par->getName(); + } else addWarning(PDERROR_CLASSPARENT_NOTFOUND,$class,$package,$class_method[1]); + if ($phpparent) $class_method[0] = $phpparent; + } else + { + $cl = $this->classes->getClassByPackage($class,$package); + } + if ($test = Converter::getConstLink($class_method[1], $class_method[0], $package)) return $test; + } + if ($test = Converter::getConstLink($expr, $class, $package)) return $test; + $cl = $this->classes->getClassByPackage($class,$package); + if ($cl) + { + $par = $cl->getParent($this); + if (is_object($par)) + { + $package = $par->docblock->package; + $class = $par->getName(); + } else $class = $par; + } else $class = false; + } while ($class); + // no links found + return false; + } + + /** + * take URL $link and text $text and return a link in the format needed for the Converter + * @param string URL + * @param string text to display + * @return string link to $link + * @abstract + */ + function returnLink($link,$text) + { + } + + /** + * take {@link abstractLink} descendant and text $eltext and return a link + * in the format needed for the Converter + * @param abstractLink + * @param string + * @return string link to $element + * @abstract + */ + function returnSee(&$link, $eltext = false) + { + } + + /** + * take {@link abstractLink} descendant and text $eltext and return a + * unique ID in the format needed for the Converter + * @param abstractLink + * @return string unique identifier of $element + * @abstract + */ + function getId(&$link) + { + } + + /** + * Convert README/INSTALL/CHANGELOG file contents to output format + * @param README|INSTALL|CHANGELOG + * @param string contents of the file + * @abstract + */ + function Convert_RIC($name, $contents) + { + } + + /** + * Convert all elements to output format + * + * This will call ConvertXxx where Xxx is {@link ucfirst}($element->type). + * It is expected that a child converter defines a handler for every + * element type, even if that handler does nothing. phpDocumentor will + * terminate with an error if a handler doesn't exist. + * {@internal + * Since 1.2.0 beta 3, this function has been moved from child converters + * to the parent, because it doesn't really make sense to put it in the + * child converter, and we can add error handling. + * + * {@source}}} + * @throws {@link PDERROR_NO_CONVERT_HANDLER} + * @param mixed {@link parserElement} descendant or {@link parserPackagePage} or {@link parserData} + */ + function Convert(&$element) + { + $handler = 'convert'.ucfirst($element->type); + if (method_exists($this,$handler)) + { + $this->$handler($element); + } else + { + addErrorDie(PDERROR_NO_CONVERTER_HANDLER,$element->type,$handler,phpDocumentor_get_class($this)); + } + } + /**#@+ + * Conversion Handlers + * + * All of the convert* handlers set up template variables for the Smarty + * template.{@internal In addition, the {@link newSmarty()} method is + * called to retrieve the global Smarty template}} + */ + /** + * Default Tutorial Handler + * + * Sets up the tutorial template, and its prev/next/parent links + * {@internal + * Retrieves the title using {@link parserTutorial::getTitle()} and uses the + * {@link parserTutorial::prev, parserTutorial::next, parserTutorial::parent} + * links to set up those links.}} + * @param parserTutorial + */ + function &convertTutorial(&$element) + { + $this->package = $element->package; + $this->subpackage = $element->subpackage; + $x = $element->Convert($this); + $template = &$this->newSmarty(); + $template->assign('contents',$x); + $template->assign('title',$element->getTitle($this)); + $template->assign('nav',$element->parent || $element->prev || $element->next); + if ($element->parent) + { + $template->assign('up',$this->getId($element->parent)); + $template->assign('uptitle',$element->parent->title); + } + if ($element->prev) + { + $template->assign('prev',$this->getId($element->prev)); + $template->assign('prevtitle',$element->prev->title); + } + if ($element->next) + { + $template->assign('next',$this->getId($element->next)); + $template->assign('nexttitle',$element->next->title); + } + return $template; + } + /** + * Default Class Handler + * + * Sets up the class template. + * {@internal special methods + * {@link generateChildClassList(), generateFormattedClassTree()}, + * {@link getFormattedConflicts, getFormattedInheritedMethods}, + * and {@link getFormattedInheritedVars} are called to complete vital + * template setup.}} + */ + function convertClass(&$element) + { + $this->class = $element->getName(); + $this->class_data = &$this->newSmarty(); + $this->class_data->assign("class_name",$element->getName()); + $this->class_data->assign("vars",array()); + $this->class_data->assign("methods",array()); + $this->class_data->assign("consts",array()); + $this->class_data->assign("is_interface", $element->isInterface()); + $this->class_data->assign("implements", $this->getFormattedImplements($element)); + $this->class_data->assign("package",$element->docblock->package); + $this->class_data->assign("line_number",$element->getLineNumber()); + $this->class_data->assign("source_location",$element->getSourceLocation($this)); + $this->class_data->assign("page_link",$this->getCurrentPageLink()); + $docblock = $this->prepareDocBlock($element, false); + $this->class_data->assign("sdesc",$docblock['sdesc']); + $this->class_data->assign("desc",$docblock['desc']); + $this->class_data->assign("access", $docblock['access']); + $this->class_data->assign("abstract", $docblock['abstract']); + $this->class_data->assign("tags",$docblock['tags']); + $this->class_data->assign("api_tags",$docblock['api_tags']); + $this->class_data->assign("info_tags",$docblock['info_tags']); + $this->class_data->assign("utags",$docblock['utags']); + if ($this->hasSourceCode($element->getPath())) { + $this->class_data->assign("class_slink",$this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true)); + } + + else + $this->class_data->assign("class_slink",false); + $this->class_data->assign("children", $this->generateChildClassList($element)); + $this->class_data->assign("class_tree", $this->generateFormattedClassTree($element)); + $this->class_data->assign("conflicts", $this->getFormattedConflicts($element,"classes")); + $inherited_methods = $this->getFormattedInheritedMethods($element); + if (!empty($inherited_methods)) + { + $this->class_data->assign("imethods",$inherited_methods); + } else + { + $this->class_data->assign("imethods",false); + } + $inherited_vars = $this->getFormattedInheritedVars($element); + if (!empty($inherited_vars)) + { + $this->class_data->assign("ivars",$inherited_vars); + } else + { + $this->class_data->assign("ivars",false); + } + $inherited_consts = $this->getFormattedInheritedConsts($element); + if (!empty($inherited_consts)) + { + $this->class_data->assign("iconsts",$inherited_consts); + } else + { + $this->class_data->assign("iconsts",false); + } + } + + + /** + * Converts method for template output + * + * This function must be called by a child converter with any extra + * template variables needed in the parameter $addition + * @param parserMethod + */ + function convertMethod(&$element, $additions = array()) + { + $fname = $element->getName(); + $docblock = $this->prepareDocBlock($element); + $returntype = 'void'; + if ($element->isConstructor) $returntype = $element->class; + if ($element->docblock->return) + { + $a = $element->docblock->return->Convert($this); + $returntype = $element->docblock->return->converted_returnType; + } + $params = $param_i = array(); + if (count($element->docblock->params)) + foreach($element->docblock->params as $param => $val) + { + $a = $val->Convert($this); + $params[] = $param_i[$param] = array("var" => $param,"datatype" => $val->converted_returnType,"data" => $a); + } + + if ($element->docblock->hasaccess) + $acc = $element->docblock->tags['access'][0]->value; + else + $acc = 'public'; + + + if ($this->hasSourceCode($element->getPath())) + $additions["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true); + $this->class_data->append('methods',array_merge( + array('sdesc' => $docblock['sdesc'], + 'desc' => $docblock['desc'], + 'access' => $docblock['access'], + 'abstract' => $docblock['abstract'], + 'tags' => $docblock['tags'], + 'api_tags' => $docblock['api_tags'], + 'info_tags' => $docblock['info_tags'], + 'utags' => $docblock['utags'], + 'constructor' => $element->isConstructor, + 'access' => $acc, + 'function_name' => $fname, + 'function_return' => $returntype, + 'function_call' => $element->getFunctionCall(), + 'ifunction_call' => $element->getIntricateFunctionCall($this, $param_i), + 'descmethod' => $this->getFormattedDescMethods($element), + 'method_overrides' => $this->getFormattedOverrides($element), + 'line_number' => $element->getLineNumber(), + 'id' => $this->getId($element), + 'params' => $params), + $additions)); + } + + /** + * Converts class variables for template output. + * + * This function must be called by a child converter with any extra + * template variables needed in the parameter $addition + * @param parserVar + */ + function convertVar(&$element, $additions = array()) + { + $docblock = $this->prepareDocBlock($element); + $b = 'mixed'; + + if ($element->docblock->hasaccess) + $acc = $element->docblock->tags['access'][0]->value; + else + $acc = 'public'; + + if ($element->docblock->var) + { + $b = $element->docblock->var->converted_returnType; + } + if ($this->hasSourceCode($element->getPath())) + $additions["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true); + $this->class_data->append('vars',array_merge( + array('sdesc' => $docblock['sdesc'], + 'desc' => $docblock['desc'], + 'abstract' => $docblock['abstract'], + 'utags' => $docblock['utags'], + 'tags' => $docblock['tags'], + 'api_tags' => $docblock['api_tags'], + 'info_tags' => $docblock['info_tags'], + 'var_name' => $element->getName(), + 'var_default' => $this->postProcess($element->getValue()), + 'var_type' => $b, + 'access' => $acc, + 'line_number' => $element->getLineNumber(), + 'descvar' => $this->getFormattedDescVars($element), + 'var_overrides' => $this->getFormattedOverrides($element), + 'id' => $this->getId($element)), + $additions)); + } + + /** + * Converts class constants for template output. + * + * This function must be called by a child converter with any extra + * template variables needed in the parameter $addition + * @param parserConst + */ + function convertConst(&$element, $additions = array()) + { + $docblock = $this->prepareDocBlock($element); + + if ($element->docblock->hasaccess) + $acc = $element->docblock->tags['access'][0]->value; + else + $acc = 'public'; + + if ($this->hasSourceCode($element->getPath())) + $additions["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true); + $this->class_data->append('consts',array_merge( + array('sdesc' => $docblock['sdesc'], + 'desc' => $docblock['desc'], + 'access' => $docblock['access'], + 'abstract' => $docblock['abstract'], + 'utags' => $docblock['utags'], + 'tags' => $docblock['tags'], + 'api_tags' => $docblock['api_tags'], + 'info_tags' => $docblock['info_tags'], + 'const_name' => $element->getName(), + 'const_value' => $this->postProcess($element->getValue()), + 'access' => $acc, + 'line_number' => $element->getLineNumber(), + 'id' => $this->getId($element)), + $additions)); + } + + /** + * Default Page Handler + * + * {@internal In addition to setting up the smarty template with {@link newSmarty()}, + * this class uses {@link getSourceLocation()} and {@link getClassesOnPage()} + * to set template variables. Also used is {@link getPageName()}, to get + * a Converter-specific name for the page.}} + * @param parserPage + */ + function convertPage(&$element) + { + $this->page_data = &$this->newSmarty(true); + $this->page = $this->getPageName($element->parent); + $this->path = $element->parent->getPath(); + $this->curpage = &$element->parent; + $this->page_data->assign("source_location",$element->parent->getSourceLocation($this)); + $this->page_data->assign("functions",array()); + $this->page_data->assign("includes",array()); + $this->page_data->assign("defines",array()); + $this->page_data->assign("globals",array()); + $this->page_data->assign("classes",$this->getClassesOnPage($element)); + $this->page_data->assign("name", $element->parent->getFile()); + if ($t = $element->getTutorial()) + { + $this->page_data->assign("tutorial",$this->returnSee($t)); + } else + { + $this->page_data->assign("tutorial",false); + } + if ($element->docblock) + { + $docblock = $this->prepareDocBlock($element, false); + $this->page_data->assign("sdesc",$docblock['sdesc']); + $this->page_data->assign("desc",$docblock['desc']); + $this->page_data->assign("tags",$docblock['tags']); + $this->page_data->assign("api_tags",$docblock['api_tags']); + $this->page_data->assign("info_tags",$docblock['info_tags']); + $this->page_data->assign("utags",$docblock['utags']); + } + } + + /** + * Converts global variables for template output + * + * This function must be called by a child converter with any extra + * template variables needed in the parameter $addition + * {@internal + * In addition to using {@link prepareDocBlock()}, this method also + * uses utility functions {@link getGlobalValue(), getFormattedConflicts()}}} + * @param parserGlobal + * @uses postProcess() on global_value template value, makes it displayable + * @param array any additional template variables should be in this array + */ + function convertGlobal(&$element, $addition = array()) + { + $docblock = $this->prepareDocBlock($element); + $value = $this->getGlobalValue($element->getValue()); + if ($this->hasSourceCode($element->getPath())) + $addition["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true); + $this->page_data->append('globals',array_merge( + array('sdesc' => $docblock['sdesc'], + 'desc' => $docblock['desc'], + 'tags' => $docblock['tags'], + 'api_tags' => $docblock['api_tags'], + 'info_tags' => $docblock['info_tags'], + 'utags' => $docblock['utags'], + 'global_name' => $element->getName(), + 'global_type' => $element->getDataType($this), + 'global_value' => $this->postProcess($value), + 'line_number' => $element->getLineNumber(), + 'global_conflicts' => $this->getFormattedConflicts($element,"global variables"), + 'id' => $this->getId($element)), + $addition)); + } + + /** + * Converts defines for template output + * + * This function must be called by a child converter with any extra + * template variables needed in the parameter $addition + * {@internal + * In addition to using {@link prepareDocBlock()}, this method also + * uses utility functions {@link getGlobalValue(), getFormattedConflicts()}}} + * @param parserDefine + * @uses postProcess() on define_value template value, makes it displayable + * @param array any additional template variables should be in this array + */ + function convertDefine(&$element, $addition = array()) + { + $docblock = $this->prepareDocBlock($element); + if ($this->hasSourceCode($element->getPath())) + $addition["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true); + $this->page_data->append('defines',array_merge( + array('sdesc' => $docblock['sdesc'], + 'desc' => $docblock['desc'], + 'tags' => $docblock['tags'], + 'api_tags' => $docblock['api_tags'], + 'info_tags' => $docblock['info_tags'], + 'utags' => $docblock['utags'], + 'define_name' => $element->getName(), + 'line_number' => $element->getLineNumber(), + 'define_value' => $this->postProcess($element->getValue()), + 'define_conflicts' => $this->getFormattedConflicts($element,"defines"), + 'id' => $this->getId($element)), + $addition)); + } + + + /** + * Converts includes for template output + * + * This function must be called by a child converter with any extra + * template variables needed in the parameter $addition + * @see prepareDocBlock() + * @param parserInclude + */ + function convertInclude(&$element, $addition = array()) + { + $docblock = $this->prepareDocBlock($element); + $per = $this->getIncludeValue($element->getValue(), $element->getPath()); + + if ($this->hasSourceCode($element->getPath())) + $addition["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true); + $this->page_data->append('includes',array_merge( + array('sdesc' => $docblock['sdesc'], + 'desc' => $docblock['desc'], + 'tags' => $docblock['tags'], + 'api_tags' => $docblock['api_tags'], + 'info_tags' => $docblock['info_tags'], + 'utags' => $docblock['utags'], + 'include_name' => $element->getName(), + 'line_number' => $element->getLineNumber(), + 'include_value' => $per), + $addition)); + } + + /** + * Converts function for template output + * + * This function must be called by a child converter with any extra + * template variables needed in the parameter $addition + * @see prepareDocBlock() + * @param parserFunction + */ + function convertFunction(&$element, $addition = array()) + { + $docblock = $this->prepareDocBlock($element); + $fname = $element->getName(); + $params = $param_i = array(); + if (count($element->docblock->params)) + foreach($element->docblock->params as $param => $val) + { + $a = $val->Convert($this); + $params[] = $param_i[$param] = array("var" => $param,"datatype" => $val->converted_returnType,"data" => $a); + } + $returntype = 'void'; + if ($element->docblock->return) + { + $a = $element->docblock->return->Convert($this); + $returntype = $element->docblock->return->converted_returnType; + } + + if ($this->hasSourceCode($element->getPath())) + $addition["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true); + $this->page_data->append('functions',array_merge( + array('sdesc' => $docblock['sdesc'], + 'desc' => $docblock['desc'], + 'tags' => $docblock['tags'], + 'api_tags' => $docblock['api_tags'], + 'info_tags' => $docblock['info_tags'], + 'utags' => $docblock['utags'], + 'function_name' => $fname, + 'function_return' => $returntype, + 'function_conflicts' => $this->getFormattedConflicts($element,"functions"), + 'ifunction_call' => $element->getIntricateFunctionCall($this, $param_i), + 'function_call' => $element->getFunctionCall(), + 'line_number' => $element->getLineNumber(), + 'id' => $this->getId($element), + 'params' => $params), + $addition)); + } + /**#@-*/ + + /** + * convert the element's DocBlock for output + * + * This function converts all tags and descriptions for output + * @param mixed any descendant of {@link parserElement}, or {@link parserData} + * @param array used to translate tagnames into other tags + * @param boolean set to false for pages and classes, the only elements allowed to specify @package + * @return array + * + * Format: + *
        +     * array('sdesc' => DocBlock summary
        +     *       'desc' => DocBlock detailed description
        +     *       'tags' => array('keyword' => tagname, 'data' => tag description)
        +     *                 known tags
        +     *       'api_tags' => array('keyword' => tagname, 'data' => tag description)
        +     *                 known api documentation tags
        +     *       'info_tags' => array('keyword' => tagname, 'data' => tag description)
        +     *                 known informational tags
        +     *     [ 'utags' => array('keyword' => tagname, 'data' => tag description
        +     *                 unknown tags ]
        +     *     [ 'vartype' => type from @var/@return tag ]
        +     *     [ 'var_descrip' => description from @var/@return tag ]
        +     *      )
        +     * 
        + */ + function prepareDocBlock(&$element, $names = array(),$nopackage = true) + { + $tagses = $element->docblock->listTags(); + $tags = $ret = $api_tags = $info_tags = array(); + $api_tags_arr = array("abstract", "access", "deprecated", "example", "filesource", + "global", "internal", "name", "return", "see", "static", + "staticvar", "uses", "var"); + if (!$nopackage) + { + $tags[] = array('keyword' => 'package','data' => $element->docblock->package); + if (!empty($element->docblock->subpackage)) $tags[] = array('keyword' => 'subpackage','data' => $element->docblock->subpackage); + } + if ($element->docblock->var) + { + $a = $element->docblock->var->Convert($this); + $ret['vartype'] = $element->docblock->var->converted_returnType; + if (!empty($a)) + { + $tags[] = array('keyword' => 'var', 'data' => $a); + $ret["var_descrip"] = $a; + } + } + if ($element->docblock->return) + { + $a = $element->docblock->return->Convert($this); + $ret['vartype'] = $element->docblock->return->converted_returnType; + if (!empty($a)) + { + $tags[] = $api_tags[] = array('keyword' => 'return', 'data' => $a); + $ret["var_descrip"] = $a; + } + } + if ($element->docblock->funcglobals) + foreach($element->docblock->funcglobals as $global => $val) + { + if ($a = $this->getGlobalLink($global,$element->docblock->package)) + { + $global = $a; + } + $b = Converter::getLink($val[0]); + if (is_object($b) && phpDocumentor_get_class($b) == 'classlink') + { + $val[0] = $this->returnSee($b); + } + $tags[] = $api_tags[] = array('keyword' => 'global','data' => $val[0].' '.$global.': '.$val[1]->Convert($this)); + } + if ($element->docblock->statics) + foreach($element->docblock->statics as $static => $val) + { + $a = $val->Convert($this); + $tags[] = $api_tags[] = array('keyword' => 'staticvar','data' => $val->converted_returnType.' '.$static.': '.$a); + } + foreach($tagses as $tag) + { + if (isset($names[$tag->keyword])) $tag->keyword = $names[$tag->keyword]; + if ($tag->keyword) + $tags[] = array("keyword" => $tag->keyword,"data" => $tag->Convert($this)); + if (in_array($tag->keyword, $api_tags_arr)) + $api_tags[] = array("keyword" => $tag->keyword,"data" => $tag->Convert($this)); + else + $info_tags[] = array("keyword" => $tag->keyword,"data" => $tag->Convert($this)); + } + $utags = array(); + foreach($element->docblock->unknown_tags as $keyword => $tag) + { + foreach($tag as $t) + $utags[] = array('keyword' => $keyword, 'data' => $t->Convert($this)); + } + $ret['abstract'] = FALSE; + $ret['access'] = 'public'; + foreach($tags as $tag) + { + if ($tag['keyword'] == 'access') + $ret['access'] = $tag['data']; + if ($tag['keyword'] == 'abstract') + $ret['abstract'] = TRUE; + } + $ret['sdesc'] = $element->docblock->getSDesc($this); + $ret['desc'] = $element->docblock->getDesc($this); + $ret['tags'] = $tags; + $ret['api_tags'] = $api_tags; + $ret['info_tags'] = $info_tags; + $ret['utags'] = $utags; + return $ret; + } + + /** + * gets a list of all classes declared on a procedural page represented by + * $element, a {@link parserData} class + * @param parserData &$element + * @return array links to each classes documentation + * + * Format: + *
        +     * array('name' => class name,
        +     *       'sdesc' => summary of the class
        +     *       'link' => link to the class's documentation)
        +     * 
        + */ + function getClassesOnPage(&$element) + { + global $_phpDocumentor_setting; + $a = $element->getClasses($this); + $classes = array(); + foreach($a as $package => $clas) + { + if (isset($_phpDocumentor_setting['packageoutput'])) + { + $packages = explode(',',$_phpDocumentor_setting['packageoutput']); + if (!in_array($package, $packages)) continue; + } + for($i=0; $iparseprivate || ! ($clas[$i]->docblock && $clas[$i]->docblock->hasaccess && $clas[$i]->docblock->tags['access'][0]->value == 'private')) + { + $sdesc = ''; + $r = array(); + $sdesc = $clas[$i]->docblock->getSDesc($this); + if ($clas[$i]->docblock->hasaccess) + $r['access'] = $clas[$i]->docblock->tags['access'][0]->value; + else + $r['access'] = 'public'; + if (isset ($clas[$i]->docblock->tags['abstract'])) + $r['abstract'] = TRUE; + else + $r['abstract'] = FALSE; + $r['name'] = $clas[$i]->getName(); + $r['sdesc'] = $sdesc; + $r['link'] = $this->getClassLink($clas[$i]->getName(),$package,$clas[$i]->getPath()); + $classes[] = $r; + } + } + } + return $classes; + } + + /** + * returns an array containing the class inheritance tree from the root + * object to the class. + * + * This method must be overridden, or phpDocumentor will halt with a fatal + * error + * @return string Converter-specific class tree for an individual class + * @param parserClass class variable + * @abstract + */ + + function generateFormattedClassTree($class) + { + addErrorDie(PDERROR_CONVERTER_OVR_GFCT,phpDocumentor_get_class($this)); + } + + /** + * returns an array containing the class inheritance tree from the root + * object to the class. + * + * This method must be overridden, or phpDocumentor will halt with a fatal + * error + * @return string Converter-specific class tree for an individual class + * @param parserClass class variable + * @abstract + */ + + function getFormattedImplements($el) + { + $ret = array(); + foreach ($el->getImplements() as $interface) + { + $ret[] = $this->returnSee($this->getLink($interface)); + } + return $ret; + } + + /** + * @param mixed {@link parserClass, parserFunction, parserDefine} or + * {@link parserGlobal} + * @param string type to display. either 'class','function','define' + * or 'global variable' + * @return array links to conflicting elements, or empty array + * @uses parserClass::getConflicts() + * @uses parserFunction::getConflicts() + * @uses parserDefine::getConflicts() + * @uses parserGlobal::getConflicts() + */ + function getFormattedConflicts(&$element,$type) + { + $conflicts = $element->getConflicts($this); + $r = array(); + if (!$conflicts) return false; + foreach($conflicts as $package => $class) + { + $r[] = $class->getLink($this,$class->docblock->package); + } + if (!empty($r)) $r = array('conflicttype' => $type, 'conflicts' => $r); + return $r; + } + + /** + * Get a list of methods in child classes that override this method + * @return array empty array or array(array('link'=>link to method, + * 'sdesc'=>short description of the method),...) + * @uses parserMethod::getOverridingMethods() + * @param parserMethod + */ + function getFormattedDescMethods(&$element) + { + $meths = $element->getOverridingMethods($this); + $r = array(); + for($i=0; $igetLink($this); + $ms['sdesc'] = $meths[$i]->docblock->getSDesc($this); + $r[] = $ms; + } + return $r; + } + + /** + * Get a list of vars in child classes that override this var + * @return array empty array or array('link'=>link to var, + * 'sdesc'=>short description of the method + * @uses parserVar::getOverridingVars() + * @param parserVar + */ + function getFormattedDescVars(&$element) + { + $vars = $element->getOverridingVars($this); + $r = array(); + for($i=0; $igetLink($this); + $vs['sdesc'] = $vars[$i]->docblock->getSDesc($this); + $r[] = $vs; + } + return $r; + } + + /** + * Get the method this method overrides, if any + * @return array|false array('link'=>link to overridden method, + * 'sdesc'=>short description + * @see parserMethod::getOverrides() + * @param parserMethod + */ + function getFormattedOverrides(&$element) + { + $ovr = $element->getOverrides($this); + if (!$ovr) return false; + $sdesc = $ovr->docblock->getSDesc($this); + return array('link' => $ovr->getLink($this),'sdesc' => $sdesc); + } + + /** + * returns a list of child classes + * + * @param parserClass class variable + * @uses parserClass::getChildClassList() + */ + + function generateChildClassList($class) + { + $kids = $class->getChildClassList($this); + $list = array(); + if (count($kids)) + { + for($i=0; $igetLink($this); + $lt['sdesc'] = $kids[$i]->docblock->getSDesc($this); + + if ($kids[$i]->docblock->hasaccess) + $lt['access'] = $kids[$i]->docblock->tags['access'][0]->value; + else + $lt['access'] = 'public'; + + $lt['abstract'] = isset ($kids[$i]->docblock->tags['abstract'][0]); + + $list[] = $lt; + } + } else return false; + return $list; + } + + /** + * Return template-enabled list of inherited variables + * + * uses parserVar helper function getInheritedVars and generates a + * template-enabled list using getClassLink() + * @param parserVar $child class method + * @see getClassLink(), parserVar::getInheritedVars() + * @return array Format: + *
        +     * array(
        +     *   array('parent_class' => link to parent class's documentation,
        +     *         'ivars' =>
        +     *            array(
        +     *              array('name' => inherited variable name,
        +     *                    'link' => link to inherited variable's documentation,
        +     *                    'default' => default value of inherited variable,
        +     *                    'sdesc' => summary of inherited variable),
        +     *              ...),
        +     *   ...)
        +     * 
        + */ + + function getFormattedInheritedVars($child) + { + $package = $child->docblock->package; + $subpackage = $child->docblock->subpackage; + $ivars = $child->getInheritedVars($this); + $results = array(); + if (!count($ivars)) return $results; + foreach($ivars as $parent => $vars) + { + $file = $vars['file']; + $vars = $vars['vars']; + $par = $this->classes->getClass($parent,$file); + $package = $par->docblock->package; + usort($vars,array($this,"sortVar")); + $result['parent_class'] = $this->getClassLink($parent,$package); + foreach($vars as $var) + { + $info = array(); + + if ($var->docblock->hasaccess) + $info['access'] = $var->docblock->tags['access'][0]->value; + else + $info['access'] = 'public'; + + $info['abstract'] = isset ($var->docblock->tags['abstract'][0]); + + $info['name'] = $var->getName(); + $info['link'] = $var->getLink($this); + $info['default'] = $this->postProcess($var->getValue()); + if ($var->docblock) + $info['sdesc'] = $var->docblock->getSDesc($this); + $result["ivars"][] = $info; + } + $results[] = $result; + $result = array(); + } + return $results; + } + + /** + * Return template-enabled list of inherited methods + * + * uses parserMethod helper function getInheritedMethods and generates a + * template-enabled list using getClassLink() + * @param parserMethod $child class method + * @see getClassLink(), parserMethod::getInheritedMethods() + * @return array Format: + *
        +     * array(
        +     *   array('parent_class' => link to parent class's documentation,
        +     *         'ivars' =>
        +     *            array(
        +     *              array('name' => inherited variable name,
        +     *                    'link' => link to inherited variable's documentation,
        +     *                    'function_call' => {@link parserMethod::getIntricateFunctionCall()}
        +     *                                       returned array,
        +     *                    'sdesc' => summary of inherited variable),
        +     *              ...),
        +     *   ...)
        +     * 
        + */ + + function getFormattedInheritedMethods($child) + { + $package = $child->docblock->package; + $subpackage = $child->docblock->subpackage; + $imethods = $child->getInheritedMethods($this); + $results = array(); + if (!count($imethods)) return $results; + foreach($imethods as $parent => $methods) + { + $file = $methods['file']; + $methods = $methods['methods']; + $par = $this->classes->getClass($parent,$file); + $package = $par->docblock->package; + usort($methods,array($this,"sortMethod")); + $result['parent_class'] = $this->getClassLink($parent,$package); + foreach($methods as $method) + { + $info = array(); + + if ($method->docblock->hasaccess) + $info['access'] = $method->docblock->tags['access'][0]->value; + else + $info['access'] = 'public'; + + $info['abstract'] = isset ($method->docblock->tags['abstract'][0]); + + if ($method->isConstructor) $info['constructor'] = 1; + $info['link'] = $method->getLink($this); + $info['name'] = $method->getName(); + if ($method->docblock) + $info['sdesc'] = $method->docblock->getSDesc($this); + $params = array(); + if (count($method->docblock->params)) + foreach($method->docblock->params as $param => $val) + { + $a = $val->Convert($this); + $params[$param] = array("var" => $param,"datatype" => $val->converted_returnType,"data" => $a); + } + + $info['function_call'] = $method->getIntricateFunctionCall($this,$params); + $result["imethods"][] = $info; + } + $results[] = $result; + $result = array(); + } + return $results; + } + + /** + * Return template-enabled list of inherited class constants + * + * uses parserConst helper function getInheritedConsts and generates a + * template-enabled list using getClassLink() + * @param parserConst $child class constant + * @see getClassLink(), parserMethod::getInheritedConsts() + * @return array Format: + *
        +     * array(
        +     *   array('parent_class' => link to parent class's documentation,
        +     *         'ivars' =>
        +     *            array(
        +     *              array('name' => inherited constant name,
        +     *                    'link' => link to inherited constant's documentation,
        +     *                    'value' => constant value,
        +     *                    'sdesc' => summary of inherited constant),
        +     *              ...),
        +     *   ...)
        +     * 
        + */ + + function getFormattedInheritedConsts($child) + { + $package = $child->docblock->package; + $subpackage = $child->docblock->subpackage; + $ivars = $child->getInheritedConsts($this); + $results = array(); + if (!count($ivars)) return $results; + foreach($ivars as $parent => $vars) + { + $file = $vars['file']; + $vars = $vars['consts']; + $par = $this->classes->getClass($parent,$file); + $package = $par->docblock->package; + usort($vars,array($this,"sortVar")); + $result['parent_class'] = $this->getClassLink($parent,$package); + foreach($vars as $var) + { + $info = array(); + + if ($var->docblock->hasaccess) + $info['access'] = $var->docblock->tags['access'][0]->value; + else + $info['access'] = 'public'; + + $info['name'] = $var->getName(); + $info['link'] = $var->getLink($this); + $info['value'] = $this->postProcess($var->getValue()); + if ($var->docblock) + $info['sdesc'] = $var->docblock->getSDesc($this); + $result["iconsts"][] = $info; + } + $results[] = $result; + $result = array(); + } + return $results; + } + + /** + * Return a Smarty template object to operate with + * + * This returns a Smarty template with pre-initialized variables for use. + * If the method "SmartyInit()" exists, it is called. + * @return Smarty + */ + function &newSmarty() + { + $templ = new Smarty; + $templ->use_sub_dirs = false; + $templ->template_dir = realpath($this->smarty_dir . PATH_DELIMITER . 'templates'); + $templ->compile_dir = realpath($this->smarty_dir . PATH_DELIMITER . 'templates_c'); + $templ->config_dir = realpath($this->smarty_dir . PATH_DELIMITER . 'configs'); + $templ->assign("date",date("r",time())); + $templ->assign("maintitle",$this->title); + $templ->assign("package",$this->package); + $templ->assign("phpdocversion",PHPDOCUMENTOR_VER); + $templ->assign("phpdocwebsite",PHPDOCUMENTOR_WEBSITE); + $templ->assign("subpackage",$this->subpackage); + if (method_exists($this,'SmartyInit')) return $this->SmartyInit($templ); + return $templ; + } + + /** + * do all necessary output + * @see Converter + * @abstract + */ + function Output($title) + { + phpDocumentor_out("WARNING: Generic Converter::Output was used, no output will be generated"); + } + + /** + * Set the template directory with a different template base directory + * @tutorial phpDocumentor.howto.pkg#using.command-line.templatebase + * @param string template base directory + * @param string template name + */ + function setTemplateBase($base, $dir) + { + // remove trailing /'s from the base path, if any + $base = str_replace('\\','/',$base); + while ($base{strlen($base) - 1} == '/') $base = substr($base,0,strlen($base) - 1); + $this->templateName = substr($dir,0,strlen($dir) - 1); + $this->templateDir = $base . "/Converters/" . $this->outputformat . "/" . $this->name . "/templates/" . $dir; + if (!is_dir($this->templateDir)) + { + addErrorDie(PDERROR_TEMPLATEDIR_DOESNT_EXIST, $this->templateDir); + } + + $this->smarty_dir = $this->templateDir; + if (file_exists($this->templateDir . PATH_DELIMITER . 'options.ini')) + { + // retrieve template options, allow array creation + $this->template_options = phpDocumentor_parse_ini_file($this->templateDir . PATH_DELIMITER . 'options.ini',true); + } + } + + /** + * sets the template directory based on the {@link $outputformat} and {@link $name} + * Also sets {@link $templateName} to the $dir parameter + * @param string subdirectory + */ + function setTemplateDir($dir) + { + if ('@DATA-DIR@' != '@'.'DATA-DIR@') { + $templateBase = str_replace('\\', '/', '@DATA-DIR@/PhpDocumentor/phpDocumentor'); + } else { + $templateBase = str_replace('\\','/',$GLOBALS['_phpDocumentor_install_dir']) . '/phpDocumentor'; + } + $this->setTemplateBase($templateBase, $dir); + } + + /** + * Get the absolute path to the converter's base directory + * @return string + */ + function getConverterDir() + { + if (/*@donotremove*/0) { + return str_replace('\\', '/', "@DATA-DIR@/PhpDocumentor/phpDocumentor/Converters/") . $this->outputformat . "/" . $this->name; + } else { + return str_replace('\\','/',$GLOBALS['_phpDocumentor_install_dir']) ."/phpDocumentor/Converters/" . $this->outputformat . "/" . $this->name; + } + } + + /** + * Parse a global variable's default value for class initialization. + * + * If a global variable's default value is "new class" as in: + * + * $globalvar = new Parser + * + * This method will document it not as "new Parser" but instead as + * "new {@link Parser}". For examples, see {@link phpdoc.inc}. + * Many global variables are classes, and phpDocumentor links to their + * documentation + * @return string default global variable value with link to class if + * it's "new Class" + * @param string default value of a global variable. + */ + function getGlobalValue($value) + { + if (strpos($value,'new') === 0) + { + preg_match('/new([^(]*)(.*)/',$value,$newval); + if (isset($newval[1])) + { + $a = Converter::getLink(trim($newval[1])); + if (!isset($newval[2])) $newval[2] = ''; + if ($a && phpDocumentor_get_class($a) == 'classlink') $value = 'new '.$this->returnSee($a).$newval[2]; + } + } + return $value; + } + + /** + * Parse an include's file to see if it is a file documented in this project + * + * Although not very smart yet, this method will try to look for the + * included file file.ext: + * + * + * include ("file.ext"); + * + * + * If it finds it, it will return a link to the file's documentation. As of + * 1.2.0rc1, phpDocumentor is smarty enough to find these cases: + *
          + *
        • absolute path to file
        • + *
        • ./file.ext or ../file.ext
        • + *
        • relpath/to/file.ext if relpath is a subdirectory of the base parse + * directory
        • + *
        + * For examples, see {@link Setup.inc.php} includes. + * Every include auto-links to the documentation for the file that is included + * @return string included file with link to docs for file, if found + * @param string file included by include statement. + * @param string path of file that has the include statement + */ + function getIncludeValue($value, $ipath) + { + preg_match('/"([^"\']*\.[^"\']*)"/',$value,$match); + if (!isset($match[1])) + preg_match('/\'([^"\']*\.[^"\']*)\'/',$value,$match); + if (isset($match[1])) + { + $fancy_per = $this->proceduralpages->pathMatchesParsedFile($match[1],$ipath); + if ($fancy_per) + { + $link = $this->addLink($fancy_per); + if (is_object($link) && phpDocumentor_get_class($link) == 'pagelink' && + isset($this->all_packages[$link->package])) + { + $value = $this->returnSee($link,$value); + } + } else + { + $per = Converter::getLink($match[1]); + if (is_object($per) && phpDocumentor_get_class($per) == 'pagelink') + $value = $this->returnSee($per); + } + } + return $value; + } + + /** + * Recursively creates all subdirectories that don't exist in the $dir path + * @param string $dir + */ + function createParentDir($dir) + { + if (empty($dir)) return; + $tmp = explode(SMART_PATH_DELIMITER,$dir); + array_pop($tmp); + $parent = implode(SMART_PATH_DELIMITER,$tmp); + if ($parent != '' && !file_exists($parent)) + { + $test = @mkdir($parent,0775); + if (!$test) + { + $this->createParentDir($parent); + $test = @mkdir($parent,0775); + phpDocumentor_out("Creating Parent Directory $parent\n"); + } else + { + phpDocumentor_out("Creating Parent Directory $parent\n"); + } + } + } + + /** + * Sets the output directory for generated documentation + * @param string $dir the output directory + */ + function setTargetDir($dir) + { + if (strlen($dir) > 0) + { + $this->targetDir = $dir; + // if directory does exist create it, this should have more error checking in the future + if (!file_exists($dir)) + { + $tmp = str_replace(array("/","\\"),SMART_PATH_DELIMITER,$dir); + if (substr($tmp,-1) == SMART_PATH_DELIMITER) + { + $tmp = substr($tmp,0,(strlen($tmp)-1)); + } + $this->createParentDir($tmp); + phpDocumentor_out("Creating Directory $dir\n"); + mkdir($dir,0775); + } + else if (!is_dir($dir)) + { + echo "Output path: '$dir' is not a directory\n"; + die(); + } + } else { + echo "a target directory must be specified\n try phpdoc -h\n"; + die(); + } + } + + /** + * Writes a file to target dir + * @param string + * @param string + * @param boolean true if the data is binary and not text + */ + function writeFile($file,$data,$binary = false) + { + if (!file_exists($this->targetDir)) + { + mkdir($this->targetDir,0775); + } + $string = ''; + if ($binary) $string = 'binary file '; + phpDocumentor_out(" Writing $string".$this->targetDir . PATH_DELIMITER . $file . "\n"); + flush(); + $write = 'w'; + if ($binary) $write = 'wb'; + $fp = fopen($this->targetDir . PATH_DELIMITER . $file,$write); + set_file_buffer( $fp, 0 ); + fwrite($fp,$data,strlen($data)); + fclose($fp); + } + + /** + * Copies a file from the template directory to the target directory + * thanks to Robert Hoffmann for this fix + * @param string + */ + function copyFile($file, $subdir = '') + { + if (!file_exists($this->targetDir)) + { + mkdir($this->targetDir,0775); + } + copy($this->templateDir . $subdir . PATH_DELIMITER . $file, $this->targetDir . PATH_DELIMITER . $file); + } + + /** + * Return parserStringWithInlineTags::Convert() cache state + * @see parserStringWithInlineTags::Convert() + * @abstract + */ + function getState() + { + return true; + } + + /** + * Compare parserStringWithInlineTags::Convert() cache state to $state + * @param mixed + * @see parserStringWithInlineTags::Convert() + * @abstract + */ + function checkState($state) + { + return true; + } + +} + +/** + * @access private + * @see Converter::getSortedClassTreeFromClass() + */ +function rootcmp($a, $b) +{ + return strnatcasecmp($a['class'],$b['class']); +} + +/** + * @access private + * @global string used to make the first tutorials converted the default package tutorials + */ +function tutorialcmp($a, $b) +{ + global $phpDocumentor_DefaultPackageName; + if ($a == $phpDocumentor_DefaultPackageName) return -1; + if ($b == $phpDocumentor_DefaultPackageName) return 1; + return strnatcasecmp($a, $b); +} + +/** + * smart htmlentities, doesn't entity the allowed tags list + * Since version 1.1, this function uses htmlspecialchars instead of + * htmlentities, for international support + * This function has been replaced by functionality in {@link ParserDescCleanup.inc} + * @param string $s + * @return string browser-displayable page + * @deprecated As of v1.2, No longer needed, as valid tags are parsed out of the source, + * and everything else is {@link Converter::postProcess()} handled + */ +function adv_htmlentities($s) +{ + return; + global $phpDocumentor___html,$_phpDocumentor_html_allowed; + $result = htmlspecialchars($s); + $entities = array_flip(get_html_translation_table(HTML_SPECIALCHARS)); + $result = strtr($result,$phpDocumentor___html); + $matches = array(); + preg_match_all('/(<img.*>)/U',$result,$matches); + for($i=0;$igetName(); + return '_'.$element->parent->getName(); + } +} +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/CHMdefaultConverter.inc b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/CHMdefaultConverter.inc new file mode 100644 index 00000000..ac38031b --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/CHMdefaultConverter.inc @@ -0,0 +1,1753 @@ + + * @since 1.0rc1 + * @version $Id: CHMdefaultConverter.inc,v 1.1 2005/10/17 18:36:57 jeichorn Exp $ + */ +/** + * Generates files that MS HTML Help Worshop can use to create a MS Windows + * compiled help file (CHM) + * + * The free MS HTML Help compiler takes the project file (phpdoc.hhp) and reads + * the table of contents file specified in the project (which is always contents.hhc + * in phpDocumentor). When the converter reaches stable state, it will also + * output an index file index.hhk. The free download for MS HTML Help Workshop + * is available below + * @link http://www.microsoft.com/downloads/release.asp?releaseid=33071 MS HTML Help Workshop download + * @package Converters + * @subpackage CHMdefault + * @author Greg Beaver + * @since 1.0rc1 + * @version $Revision: 1.1 $ + */ +class CHMdefaultConverter extends Converter +{ + /** + * CHMdefaultConverter wants elements sorted by type as well as alphabetically + * @see Converter::$sort_page_contents_by_type + * @var boolean + */ + var $sort_page_contents_by_type = true; + /** @var string */ + var $outputformat = 'CHM'; + /** @var string */ + var $name = 'default'; + /** + * indexes of elements by package that need to be generated + * @var array + */ + var $leftindex = array('classes' => true, 'pages' => true, 'functions' => true, 'defines' => false, 'globals' => false); + + /** + * output directory for the current procedural page being processed + * @var string + */ + var $page_dir; + + /** + * target directory passed on the command-line. + * {@link $targetDir} is malleable, always adding package/ and package/subpackage/ subdirectories onto it. + * @var string + */ + var $base_dir; + + /** + * output directory for the current class being processed + * @var string + */ + var $class_dir; + + /** + * array of converted package page names. + * Used to link to the package page in the left index + * @var array Format: array(package => 1) + */ + var $package_pages = array(); + + /** + * controls formatting of parser informative output + * + * Converter prints: + * "Converting /path/to/file.php... Procedural Page Elements... Classes..." + * Since CHMdefaultConverter outputs files while converting, it needs to send a \n to start a new line. However, if there + * is more than one class, output is messy, with multiple \n's just between class file output. This variable prevents that + * and is purely cosmetic + * @var boolean + */ + var $juststarted = false; + + /** + * contains all of the template procedural page element loop data needed for the current template + * @var array + */ + var $current; + + /** + * contains all of the template class element loop data needed for the current template + * @var array + */ + var $currentclass; + var $wrote = false; + var $ric_set = array(); + /** + * Table of Contents entry for index.hhk + * @var array + */ + var $KLinks = array(); + + /** + * sets {@link $base_dir} to $targetDir + * @see Converter() + */ + function CHMdefaultConverter(&$allp, &$packp, &$classes, &$procpages, $po, $pp, $qm, $targetDir, $templateDir, $title) + { + Converter::Converter($allp, $packp, $classes, $procpages,$po, $pp, $qm, $targetDir, $templateDir, $title); + $this->base_dir = $targetDir; + } + + /** + * @deprecated in favor of PHP 4.3.0+ tokenizer-based source highlighting + */ + function unmangle($sourcecode) + { + $sourcecode = str_replace('','
        ',$sourcecode);
        +        $sourcecode = str_replace('','
        ',$sourcecode); + $sourcecode = str_replace('
        ',"\n",$sourcecode); + $sourcecode = str_replace(' ',' ',$sourcecode); + $sourcecode = str_replace('<','<',$sourcecode); + $sourcecode = str_replace('>','>',$sourcecode); + $sourcecode = str_replace('&','&',$sourcecode); + return $sourcecode; + } + + /** + * @param string full path to the source file + * @param string fully highlighted source code + */ + function writeSource($path, $value) + { + $templ = &$this->newSmarty(); + $pathinfo = $this->proceduralpages->getPathInfo($path, $this); + $templ->assign('source',$value); + $templ->assign('package',$pathinfo['package']); + $templ->assign('subpackage',$pathinfo['subpackage']); + $templ->assign('name',$pathinfo['name']); + $templ->assign('source_loc',$pathinfo['source_loc']); + $templ->assign('docs',$pathinfo['docs']); + $templ->assign("subdir",'../'); + $templ->register_outputfilter('CHMdefault_outputfilter'); + $this->setTargetDir($this->getFileSourcePath($this->base_dir)); + $this->addSourceTOC($pathinfo['name'],$this->getFileSourceName($path),$pathinfo['package'],$pathinfo['subpackage'], true); + phpDocumentor_out("\n"); + $this->setSourcePaths($path); + $this->writefile($this->getFileSourceName($path).'.html',$templ->fetch('filesource.tpl')); + } + + function writeExample($title, $path, $source) + { + $templ = &$this->newSmarty(); + $templ->assign('source',$source); + if (empty($title)) + { + $title = 'example'; + addWarning(PDERROR_EMPTY_EXAMPLE_TITLE, $path, $title); + } + $templ->assign('title',$title); + $templ->assign('file',$path); + $templ->assign("subdir",'../'); + $templ->register_outputfilter('CHMdefault_outputfilter'); + $pathinfo = $this->proceduralpages->getPathInfo($path, $this); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . '__examplesource'); + $this->addSourceTOC($title,'exsource_'.$path,$pathinfo['package'],$pathinfo['subpackage'], false); + phpDocumentor_out("\n"); + $this->writefile('exsource_'.$path.'.html',$templ->fetch('examplesource.tpl')); + } + + function getExampleLink($path, $title) + { + return $this->returnLink('{$subdir}__examplesource' . PATH_DELIMITER . 'exsource_'.$path.'.html',$title); + } + + function getSourceLink($path) + { + // fix 1171583 + $x = str_replace(PATH_DELIMITER, '', $this->getFileSourcePath('{$subdir}')) . + PATH_DELIMITER; + return $this->returnLink($x . + $this->getFileSourceName($path).'.html','Source Code for this file'); + } + + /** + * Used to convert the <> tag in a docblock + * @param string + * @param boolean + * @return string + */ + function ProgramExample($example, $tutorial = false, $inlinesourceparse = null/*false*/, + $class = null/*false*/, $linenum = null/*false*/, $filesourcepath = null/*false*/) + { + return $this->PreserveWhiteSpace(parent::ProgramExample($example, $tutorial, $inlinesourceparse, $class, $linenum, $filesourcepath)); + } + + /** + * @param string + */ + function TutorialExample($example) + { + $trans = $this->template_options['desctranslate']; + $this->template_options['desctranslate'] = array(); + $example = '
          ' . parent::TutorialExample($example) + .'
        '; + $this->template_options['desctranslate'] = $trans; + if (!isset($this->template_options['desctranslate'])) return $example; + if (!isset($this->template_options['desctranslate']['code'])) return $example; + $example = $this->template_options['desctranslate']['code'] . $example; + if (!isset($this->template_options['desctranslate']['/code'])) return $example; + return $example . $this->template_options['desctranslate']['/code']; + } + + /** + * Retrieve a Converter-specific anchor to a segment of a source code file + * parsed via a {@tutorial tags.filesource.pkg} tag. + * @param string full path to source file + * @param string name of anchor + * @param string link text, if this is a link + * @param boolean returns either a link or a destination based on this + * parameter + * @return string link to an anchor, or the anchor + */ + function getSourceAnchor($sourcefile,$anchor,$text = '',$link = false) + { + if ($link) { + $x = str_replace(PATH_DELIMITER, '', $this->getFileSourcePath('{$subdir}')) . + PATH_DELIMITER; + return $this->returnLink($x . + $this->getFileSourceName($sourcefile).'.html#a'.$anchor, $text); + } else + return ''; + } + + function getCurrentPageLink() + { + return $this->curname . '.html'; + } + + /** + * Uses htmlspecialchars() on the input + */ + function postProcess($text) + { + return htmlspecialchars($text); + } + + /** + * Use the template tutorial_toc.tpl to generate a table of contents for HTML + * @return string table of contents formatted for use in the current output format + * @param array format: array(array('tagname' => section, 'link' => returnsee link, 'id' => anchor name, 'title' => from title tag),...) + */ + function formatTutorialTOC($toc) + { + $template = &$this->newSmarty(); + $template->assign('toc',$toc); + return $template->fetch('tutorial_toc.tpl'); + } + + function &SmartyInit(&$templ) + { + if (!isset($this->package_index)) + foreach($this->all_packages as $key => $val) + { + if (isset($this->pkg_elements[$key])) + { + if (!isset($start)) $start = $key; + $this->package_index[] = array('link' => "li_$key.html", 'title' => $key); + } + } + $templ->assign("packageindex",$this->package_index); + $templ->assign("subdir",''); + return $templ; + } + + + /** + * Writes out the template file of {@link $class_data} and unsets the template to save memory + * @see registerCurrentClass() + * @see parent::endClass() + */ + function endClass() + { + $a = '../'; + if (!empty($this->subpackage)) $a .= '../'; + if ($this->juststarted) + { + $this->juststarted = false; + phpDocumentor_out("\n"); + flush(); + } + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->class_dir); + $this->class_data->assign("subdir",$a); + $this->class_data->register_outputfilter('CHMdefault_outputfilter'); + $this->addTOC($this->class,$this->class,$this->package,$this->subpackage, true); + $this->writefile($this->class . '.html',$this->class_data->fetch('class.tpl')); + unset($this->class_data); + } + + /** + * Writes out the template file of {@link $page_data} and unsets the template to save memory + * @see registerCurrent() + * @see parent::endPage() + */ + function endPage() + { + $this->package = $this->curpage->package; + $this->subpackage = $this->curpage->subpackage; + $a = '../'; + if (!empty($this->subpackage)) $a .= '../'; + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->page_dir); + $this->page_data->assign("package",$this->package); + $this->page_data->assign("subdir",$a); + $this->page_data->register_outputfilter('CHMdefault_outputfilter'); + $this->addTOC($this->curpage->file,$this->page,$this->package,$this->subpackage); + $this->writefile($this->page . '.html',$this->page_data->fetch('page.tpl')); + unset($this->page_data); + } + + /** + * @param string + * @param string + * @return string <a href="'.$link.'">'.$text.''.$text.''; + } + + /** + * CHMdefaultConverter chooses to format both package indexes and the complete index here + * + * This function formats output for the elementindex.html and pkgelementindex.html template files. It then + * writes them to the target directory + * @see generateElementIndex(), generatePkgElementIndex() + */ + function formatPkgIndex() + { + list($package_indexes,$packages,$mletters) = $this->generatePkgElementIndexes(); + for($i=0;$inewSmarty(); + $this->package = $package_indexes[$i]['package']; + $this->subpackage = ''; + $template->assign("index",$package_indexes[$i]['pindex']); + $template->assign("package",$package_indexes[$i]['package']); + $template->assign("letters",$mletters[$package_indexes[$i]['package']]); + $template->assign("title","Package ".$package_indexes[$i]['package']." Element Index"); + $template->assign("subdir",'../'); + $template->register_outputfilter('CHMdefault_outputfilter'); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $package_indexes[$i]['package']); + $this->addTOC($package_indexes[$i]['package']." Alphabetical Index",'elementindex_'.$package_indexes[$i]['package'],$package_indexes[$i]['package'],''); + $this->writefile('elementindex_'.$package_indexes[$i]['package'].'.html',$template->fetch('pkgelementindex.tpl')); + } + phpDocumentor_out("\n"); + flush(); + } + + /** + * CHMdefaultConverter uses this function to format template index.html and packages.html + * + * This function generates the package list from {@link $all_packages}, eliminating any + * packages that don't have any entries in their package index (no files at all, due to @ignore + * or other factors). Then it uses the default package name as the first package index to display. + * It sets the right pane to be either a blank file with instructions on making package-level docs, + * or the package-level docs for the default package. + * @global string Used to set the starting package to display + */ + function formatIndex() + { + global $phpDocumentor_DefaultPackageName; + list($elindex,$mletters) = $this->generateElementIndex(); + $template = &$this->newSmarty(); + $template->assign("index",$elindex); + $template->assign("letters",$mletters); + $template->assign("title","Element Index"); + $template->assign("date",date("r",time())); + $template->register_outputfilter('CHMdefault_outputfilter'); + phpDocumentor_out("\n"); + flush(); + $this->setTargetDir($this->base_dir); + $this->addTOC("Alphabetical Index Of All Elements",'elementindex',"Index",''); + $this->writefile('elementindex.html',$template->fetch('elementindex.tpl')); + usort($this->package_index,"CHMdefault_pindexcmp"); + $index = &$this->newSmarty(); + foreach($this->all_packages as $key => $val) + { + if (isset($this->pkg_elements[$key])) + { + if (!isset($start)) $start = $key; + if (!isset($this->package_pages[$key])) $this->writeNewPPage($key); + } + } + $this->setTargetDir($this->base_dir); + // Created index.html + if (isset($this->pkg_elements[$phpDocumentor_DefaultPackageName])) $start = $phpDocumentor_DefaultPackageName; + $this->package = $start; + $this->subpackage = ''; + $setalready = false; + if (isset($this->tutorials[$start]['']['pkg'])) + { + foreach($this->tutorials[$start]['']['pkg'] as $tute) + { + if ($tute->name == $start . '.pkg') + { + $setalready = true; + $this->addTOC("Start page",$start.'/tutorial_'.$tute->name,"Index",''); + } + } + } + if (!$setalready) + { + if (isset($this->package_pages[$start])) + { + $this->addTOC("Start page",'package_'.$start,"Index",''); + } + else + { + $index->assign("blank","blank"); + $blank = &$this->newSmarty(); + $blank->assign('package',$phpDocumentor_DefaultPackageName); + $this->addTOC("Start page",'blank',"Index",''); + $this->writefile("blank.html",$blank->fetch('blank.tpl')); + Converter::writefile('index.html',$blank->fetch('tutorial.tpl')); + } + } + phpDocumentor_out("\n"); + flush(); + + unset($index); + } + + function writeNewPPage($key) + { + return; + $template = &$this->newSmarty(); + $this->package = $key; + $this->subpackage = ''; + $template->assign("date",date("r",time())); + $template->assign("title",$this->title); + $template->assign("package",$key); + $template->register_outputfilter('CHMdefault_outputfilter'); + phpDocumentor_out("\n"); + flush(); + $this->setTargetDir($this->base_dir); + + $this->addTOC("$key Index","li_$key",$key,''); + $this->writefile("li_$key.html",$template->fetch('index.tpl')); + unset($template); + } + + /** + * Generate indexes for li_package.html and classtree output files + * + * This function generates the li_package.html files from the template file left.html. It does this by + * iterating through each of the $page_elements, $class_elements and $function_elements arrays to retrieve + * the pre-sorted {@link abstractLink} descendants needed for index generation. Conversion of these links to + * text is done by {@link returnSee()}. The {@link $local} parameter is set to false to ensure that paths are correct. + * + * Then it uses {@link generateFormattedClassTrees()} to create class trees from the template file classtrees.html. Output + * filename is classtrees_packagename.html. This function also unsets {@link $elements} and {@link $pkg_elements} to free + * up the considerable memory these two class vars use + * @see $page_elements, $class_elements, $function_elements + */ + function formatLeftIndex() + { + phpDocumentor_out("\n"); + flush(); + $this->setTargetDir($this->base_dir); + if (0)//!isset($this->left)) + { + debug("Nothing parsed, check the command-line"); + die(); + } + foreach($this->all_packages as $package => $rest) + { + if (!isset($this->pkg_elements[$package])) continue; + + // Create class tree page + $template = &$this->newSmarty(); + $template->assign("classtrees",$this->generateFormattedClassTrees($package)); + $template->assign("package",$package); + $template->assign("date",date("r",time())); + $template->register_outputfilter('CHMdefault_outputfilter'); + $this->addTOC("$package Class Trees","classtrees_$package",$package,''); + $this->writefile("classtrees_$package.html",$template->fetch('classtrees.tpl')); + phpDocumentor_out("\n"); + flush(); + } + // free up considerable memory + unset($this->elements); + unset($this->pkg_elements); + } + + /** + * This function takes an {@link abstractLink} descendant and returns an html link + * + * @param abstractLink a descendant of abstractlink should be passed, and never text + * @param string text to display in the link + * @param boolean this parameter is not used, and is deprecated + * @param boolean determines whether the returned text is enclosed in an tag + */ + function returnSee(&$element, $eltext = false, $with_a = true) + { + if (!$element) return false; + if (!$with_a) return $this->getId($element, false); + if (!$eltext) + { + $eltext = ''; + switch($element->type) + { + case 'tutorial' : + $eltext = strip_tags($element->title); + break; + case 'method' : + case 'var' : + case 'const' : + $eltext .= $element->class.'::'; + case 'page' : + case 'define' : + case 'class' : + case 'function' : + case 'global' : + default : + $eltext .= $element->name; + if ($element->type == 'function' || $element->type == 'method') $eltext .= '()'; + break; + } + } + return ''.$eltext.''; + } + + function getId($element, $fullpath = true) + { + if (phpDocumentor_get_class($element) == 'parserdata') + { + $element = $this->addLink($element->parent); + $elp = $element->parent; + } elseif (is_a($element, 'parserbase')) + { + $elp = $element; + $element = $this->addLink($element); + } + $c = ''; + if (!empty($element->subpackage)) + { + $c = '/'.$element->subpackage; + } + $b = '{$subdir}'; + switch ($element->type) + { + case 'page' : + if ($fullpath) + return $b.$element->package.$c.'/'.$element->fileAlias.'.html'; + return 'top'; + break; + case 'define' : + case 'global' : + case 'function' : + if ($fullpath) + return $b.$element->package.$c.'/'.$element->fileAlias.'.html#'.$element->type.$element->name; + return $element->type.$element->name; + break; + case 'class' : + if ($fullpath) + return $b.$element->package.$c.'/'.$element->name.'.html'; + return 'top'; + break; + case 'method' : + case 'var' : + case 'const' : + if ($fullpath) + return $b.$element->package.$c.'/'.$element->class.'.html#'.$element->type.$element->name; + return $element->type.$element->name; + break; + case 'tutorial' : + $d = ''; + if ($element->section) + { + $d = '#'.$element->section; + } + return $b.$element->package.$c.'/tutorial_'.$element->name.'.html'.$d; + } + } + + function ConvertTodoList() + { + $todolist = array(); + foreach($this->todoList as $package => $alltodos) + { + foreach($alltodos as $todos) + { + $converted = array(); + $converted['link'] = $this->returnSee($todos[0]); + if (!is_array($todos[1])) + { + $converted['todos'][] = $todos[1]->Convert($this); + } else + { + foreach($todos[1] as $todo) + { + $converted['todos'][] = $todo->Convert($this); + } + } + $todolist[$package][] = $converted; + } + } + $templ = &$this->newSmarty(); + $templ->assign('todos',$todolist); + $templ->register_outputfilter('CHMdefault_outputfilter'); + $this->setTargetDir($this->base_dir); + $this->addTOC('Todo List','todolist','Index','',false,true); + $this->addKLink('Todo List', 'todolist', '', 'Development'); + $this->writefile('todolist.html',$templ->fetch('todolist.tpl')); + } + + /** + * Convert README/INSTALL/CHANGELOG file contents to output format + * @param README|INSTALL|CHANGELOG + * @param string contents of the file + */ + function Convert_RIC($name, $contents) + { + $template = &$this->newSmarty(); + $template->assign('contents',$contents); + $template->assign('name',$name); + $this->setTargetDir($this->base_dir); + $this->addTOC($name,'ric_'.$name,'Index','',false,true); + $this->addKLink($name, 'ric_'.$name, '', 'Development'); + $this->writefile('ric_'.$name . '.html',$template->fetch('ric.tpl')); + $this->ric_set[$name] = true; + } + + /** + * Create errors.html template file output + * + * This method takes all parsing errors and warnings and spits them out ordered by file and line number. + * @global ErrorTracker We'll be using it's output facility + */ + function ConvertErrorLog() + { + global $phpDocumentor_errors; + $allfiles = array(); + $files = array(); + $warnings = $phpDocumentor_errors->returnWarnings(); + $errors = $phpDocumentor_errors->returnErrors(); + $template = &$this->newSmarty(); + foreach($warnings as $warning) + { + $file = '##none'; + $linenum = 'Warning'; + if ($warning->file) + { + $file = $warning->file; + $allfiles[$file] = 1; + $linenum .= ' on line '.$warning->linenum; + } + $files[$file]['warnings'][] = array('name' => $linenum, 'listing' => $warning->data); + } + foreach($errors as $error) + { + $file = '##none'; + $linenum = 'Error'; + if ($error->file) + { + $file = $error->file; + $allfiles[$file] = 1; + $linenum .= ' on line '.$error->linenum; + } + $files[$file]['errors'][] = array('name' => $linenum, 'listing' => $error->data); + } + $i=1; + $af = array(); + foreach($allfiles as $file => $num) + { + $af[$i++] = $file; + } + $allfiles = $af; + usort($allfiles,'strnatcasecmp'); + $allfiles[0] = "Post-parsing"; + foreach($allfiles as $i => $a) + { + $allfiles[$i] = array('file' => $a); + } + $out = array(); + foreach($files as $file => $data) + { + if ($file == '##none') $file = 'Post-parsing'; + $out[$file] = $data; + } + $template->assign("files",$allfiles); + $template->assign("all",$out); + $template->assign("title","phpDocumentor Parser Errors and Warnings"); + $this->setTargetDir($this->base_dir); + $this->writefile("errors.html",$template->fetch('errors.tpl')); + unset($template); + phpDocumentor_out("\n\nTo view errors and warnings, look at ".$this->base_dir. PATH_DELIMITER . "errors.html\n"); + flush(); + } + + function getCData($value) + { + return '
        '.htmlentities($value).'
        '; + } + + function getTutorialId($package,$subpackage,$tutorial,$id) + { + return $id; + } + + /** + * Converts package page and sets its package as used in {@link $package_pages} + * @param parserPackagePage + */ + function convertPackagepage(&$element) + { + phpDocumentor_out("\n"); + flush(); + $this->package = $element->package; + $this->subpackage = ''; + $contents = $element->Convert($this); + $this->package_pages[$element->package] = str_replace('{$subdir}','../',$contents); + phpDocumentor_out("\n"); + flush(); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $element->package); + $this->addTOC($element->package." Tutorial",'package_'.$element->package,$element->package,''); + $this->writeFile('package_'.$element->package.'.html',str_replace('{$subdir}','../',$contents)); + $this->setTargetDir($this->base_dir); + Converter::writefile('index.html',str_replace('{$subdir}','',$contents)); + $this->addKLink($element->package." Tutorial", 'package_'.$element->package, '', 'Tutorials'); + } + + /** + * @param parserTutorial + */ + function convertTutorial(&$element) + { + phpDocumentor_out("\n"); + flush(); + $template = &parent::convertTutorial($element); + $a = '../'; + if ($element->subpackage) $a .= '../'; + $template->assign('subdir',$a); + $template->register_outputfilter('CHMdefault_outputfilter'); + $contents = $template->fetch('tutorial.tpl'); + if ($element->package == $GLOBALS['phpDocumentor_DefaultPackageName'] && empty($element->subpackage) && ($element->name == $element->package . '.pkg')) + { + $template->assign('subdir',''); + $this->setTargetDir($this->base_dir); + Converter::writefile('index.html',$template->fetch('tutorial.tpl')); + } + $a = ''; + if ($element->subpackage) $a = PATH_DELIMITER . $element->subpackage; + phpDocumentor_out("\n"); + flush(); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $element->package . $a); + $this->addTOC($a = strip_tags($element->getTitle($this)), 'tutorial_'.$element->name, + $element->package, $element->subpackage, false, true); + $this->writeFile('tutorial_'.$element->name.'.html',$contents); + $this->addKLink($element->getTitle($this), $element->package . $a . PATH_DELIMITER . 'tutorial_'.$element->name, + '', 'Tutorials'); + } + + /** + * Converts class for template output + * @see prepareDocBlock(), generateChildClassList(), generateFormattedClassTree(), getFormattedConflicts() + * @see getFormattedInheritedMethods(), getFormattedInheritedVars() + * @param parserClass + */ + function convertClass(&$element) + { + parent::convertClass($element); + $this->class_dir = $element->docblock->package; + if (!empty($element->docblock->subpackage)) $this->class_dir .= PATH_DELIMITER . $element->docblock->subpackage; + $a = '../'; + if ($element->docblock->subpackage != '') $a = "../$a"; + + $this->class_data->assign('subdir',$a); + $this->class_data->assign("title","Docs For Class " . $element->getName()); + $this->class_data->assign("page",$element->getName() . '.html'); + $this->addKLink($element->name, $this->class_dir . PATH_DELIMITER . $this->class, '', 'Classes'); + } + + + /** + * Converts class variables for template output + * @see prepareDocBlock(), getFormattedConflicts() + * @param parserDefine + */ + function convertVar(&$element) + { + parent::convertVar($element, array('var_dest' => $this->getId($element,false))); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->class_dir); + $this->addKLink($element->name, $this->class_dir . PATH_DELIMITER .$this->class, $this->getId($element,false), $element->class.' Properties'); + } + + /** + * Converts class constants for template output + * @see prepareDocBlock(), getFormattedConflicts() + * @param parserDefine + */ + function convertConst(&$element) + { + parent::convertConst($element, array('const_dest' => $this->getId($element,false))); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->class_dir); + $this->addKLink($element->name, $this->class_dir . PATH_DELIMITER .$this->class, $this->getId($element,false), $element->class.' Constants'); + } + + /** + * Converts class methods for template output + * @see prepareDocBlock(), getFormattedConflicts() + * @param parserDefine + */ + function convertMethod(&$element) + { + parent::convertMethod($element, array('method_dest' => $this->getId($element,false))); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->class_dir); + $this->addKLink($element->name, $this->class_dir . PATH_DELIMITER .$this->class, $this->getId($element,false), $element->class.' Methods'); + } + + /** + * Converts function for template output + * @see prepareDocBlock(), parserFunction::getFunctionCall(), getFormattedConflicts() + * @param parserFunction + */ + function convertFunction(&$element) + { + $funcloc = $this->getId($this->addLink($element)); + parent::convertFunction($element,array('function_dest' => $this->getId($element,false))); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->page_dir); + $this->addKLink($element->name, $this->page_dir . PATH_DELIMITER . $this->page, $this->getId($element,false), 'Functions'); + } + + /** + * Converts include elements for template output + * @see prepareDocBlock() + * @param parserInclude + */ + function convertInclude(&$element) + { + parent::convertInclude($element, array('include_file' => '_'.strtr($element->getValue(),array('"' => '', "'" => '','.' => '_')))); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->page_dir); + $this->addKLink(str_replace('"', '', $element->getValue()), $this->page_dir . PATH_DELIMITER . $this->page, '', ucfirst($element->name)); + } + + /** + * Converts defines for template output + * @see prepareDocBlock(), getFormattedConflicts() + * @param parserDefine + */ + function convertDefine(&$element) + { + parent::convertDefine($element, array('define_link' => $this->getId($element,false))); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->page_dir); + $this->addKLink($element->name, $this->page_dir . PATH_DELIMITER . $this->page, $this->getId($element,false), 'Constants'); + } + + /** + * Converts global variables for template output + * @param parserGlobal + */ + function convertGlobal(&$element) + { + parent::convertGlobal($element, array('global_link' => $this->getId($element,false))); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->page_dir); + $this->addKLink($element->name, $this->page_dir . PATH_DELIMITER . $this->page, $this->getId($element,false), 'Global Variables'); + } + + /** + * converts procedural pages for template output + * @see prepareDocBlock(), getClassesOnPage() + * @param parserData + */ + function convertPage(&$element) + { + parent::convertPage($element); + $this->juststarted = true; + $this->page_dir = $element->parent->package; + if (!empty($element->parent->subpackage)) $this->page_dir .= PATH_DELIMITER . $element->parent->subpackage; + // registering stuff on the template + $this->page_data->assign("page",$this->getPageName($element) . '.html'); + $this->page_data->assign("title","Docs for page ".$element->parent->getFile()); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->page_dir); + $this->addKLink($element->parent->file, $this->page_dir . PATH_DELIMITER . $this->page, '', 'Files'); + } + + function getPageName(&$element) + { + if (phpDocumentor_get_class($element) == 'parserpage') return '_'.$element->getName(); + return '_'.$element->parent->getName(); + } + + /** + * returns an array containing the class inheritance tree from the root object to the class + * + * @param parserClass class variable + * @return array Format: array(root,child,child,child,...,$class) + * @uses parserClass::getParentClassTree() + */ + + function generateFormattedClassTree($class) + { + $tree = $class->getParentClassTree($this); + $out = ''; + if (count($tree) - 1) + { + $result = array($class->getName()); + $parent = $tree[$class->getName()]; + $distance[] = ''; + while ($parent) + { + $x = $parent; + if (is_object($parent)) + { + $subpackage = $parent->docblock->subpackage; + $package = $parent->docblock->package; + $x = $parent; + $x = $parent->getLink($this); + if (!$x) $x = $parent->getName(); + } + $result[] = + $x; + $distance[] = + "\n%s|\n" . + "%s--"; + if (is_object($parent)) + $parent = $tree[$parent->getName()]; + elseif (isset($tree[$parent])) + $parent = $tree[$parent]; + } + $nbsp = ' '; + for($i=count($result) - 1;$i>=0;$i--) + { + $my_nbsp = ''; + for($j=0;$jarray_reverse($result),'distance'=>array_reverse($distance)); + } else + { + return array('classes'=>$class->getName(),'distance'=>array('')); + } + } + + /** @access private */ + function sortVar($a, $b) + { + return strnatcasecmp($a->getName(),$b->getName()); + } + + /** @access private */ + function sortMethod($a, $b) + { + if ($a->isConstructor) return -1; + if ($b->isConstructor) return 1; + return strnatcasecmp($a->getName(),$b->getName()); + } + + /** + * returns a template-enabled array of class trees + * + * @param string $package package to generate a class tree for + * @see $roots, HTMLConverter::getRootTree() + */ + function generateFormattedClassTrees($package) + { + if (!isset($this->roots[$package])) return array(); + $roots = $trees = array(); + $roots = $this->roots[$package]; + for($i=0;$i $roots[$i],'class_tree' => "
          \n".$this->getRootTree($this->getSortedClassTreeFromClass($roots[$i],$package,''),$package)."
        \n"); + } + return $trees; + } + + /** + * return formatted class tree for the Class Trees page + * + * @param array $tree output from {@link getSortedClassTreeFromClass()} + * @see Classes::$definitechild, generateFormattedClassTrees() + * @return string + */ + function getRootTree($tree,$package) + { + if (!$tree) return ''; + $my_tree = ''; + $cur = '#root'; + $lastcur = array(false); + $kids = array(); + $dopar = false; + if ($tree[$cur]['parent']) + { + $dopar = true; + if (!is_object($tree[$cur]['parent'])) + { +// debug("parent ".$tree[$cur]['parent']." not found"); + $my_tree .= '
      • ' . $tree[$cur]['parent'] .'
          '; + } + else + { +// debug("parent ".$this->returnSee($tree[$cur]['parent'])." in other package"); + $my_tree .= '
        • ' . $this->returnSee($tree[$cur]['parent']); + if ($tree[$cur]['parent']->package != $package) $my_tree .= ' (Different package)
            '; + } + } + do + { +// fancy_debug($cur,$lastcur,$kids); + if (count($tree[$cur]['children'])) + { +// debug("$cur has children"); + if (!isset($kids[$cur])) + { +// debug("set $cur kids"); + $kids[$cur] = 1; + $my_tree .= '
          • '.$this->returnSee($tree[$cur]['link']); + $my_tree .= '
              '."\n"; + } + array_push($lastcur,$cur); + list(,$cur) = each($tree[$cur]['children']); +// var_dump('listed',$cur); + if ($cur) + { + $cur = $cur['package'] . '#' . $cur['class']; +// debug("set cur to child $cur"); +// $my_tree .= '
            • '.$this->returnSee($tree[$cur]['link']); + continue; + } else + { +// debug("end of children for $cur"); + $cur = array_pop($lastcur); + $cur = array_pop($lastcur); + $my_tree .= '
          • '."\n"; + if ($dopar && ($cur == '#root' || !$cur)) $my_tree .= '
        • '; + } + } else + { +// debug("$cur has no children"); + $my_tree .= '
        • '.$this->returnSee($tree[$cur]['link'])."
        • "; + if ($dopar && $cur == '#root') $my_tree .= '
      • '; + $cur = array_pop($lastcur); + } + } while ($cur); + return $my_tree; + } + /** + * Generate indexing information for given element + * + * @param parserElement descendant of parserElement + * @see generateElementIndex() + * @return array + */ + function getIndexInformation($elt) + { + $Result['type'] = $elt->type; + $Result['file_name'] = $elt->file; + $Result['path'] = $elt->getPath(); + + if (isset($elt->docblock)) + { + $Result['description'] = $elt->docblock->getSDesc($this); + + if ($elt->docblock->hasaccess) + $Result['access'] = $elt->docblock->tags['access'][0]->value; + else + $Result['access'] = 'public'; + + $Result['abstract'] = isset ($elt->docblock->tags['abstract'][0]); + } + else + $Result['description'] = ''; + + $aa = $Result['description']; + if (!empty($aa)) $aa = "
            $aa"; + + switch($elt->type) + { + case 'class': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Class'; + $Result['link'] = $this->getClassLink($elt->getName(), + $elt->docblock->package, + $elt->getPath(), + $elt->getName()); + $Result['listing'] = 'in file '.$elt->file.', class '.$Result['link']."$aa"; + break; + case 'define': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Constant'; + $Result['link'] = $this->getDefineLink($elt->getName(), + $elt->docblock->package, + $elt->getPath(), + $elt->getName()); + $Result['listing'] = 'in file '.$elt->file.', constant '.$Result['link']."$aa"; + break; + case 'global': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Global'; + $Result['link'] = $this->getGlobalLink($elt->getName(), + $elt->docblock->package, + $elt->getPath(), + $elt->getName()); + $Result['listing'] = 'in file '.$elt->file.', global variable '.$Result['link']."$aa"; + break; + case 'function': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Function'; + $Result['link'] = $this->getFunctionLink($elt->getName(), + $elt->docblock->package, + $elt->getPath(), + $elt->getName().'()'); + $Result['listing'] = 'in file '.$elt->file.', function '.$Result['link']."$aa"; + break; + case 'method': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Method'; + $Result['link'] = $this->getMethodLink($elt->getName(), + $elt->class, + $elt->docblock->package, + $elt->getPath(), + $elt->class.'::'.$elt->getName().'()' + ); + if ($elt->isConstructor) $Result['constructor'] = 1; + $Result['listing'] = 'in file '.$elt->file.', method '.$Result['link']."$aa"; + break; + case 'var': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Variable'; + $Result['link'] = $this->getVarLink($elt->getName(), + $elt->class, + $elt->docblock->package, + $elt->getPath(), + $elt->class.'::'.$elt->getName()); + $Result['listing'] = 'in file '.$elt->file.', variable '.$Result['link']."$aa"; + break; + case 'const': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Variable'; + $Result['link'] = $this->getConstLink($elt->getName(), + $elt->class, + $elt->docblock->package, + $elt->getPath(), + $elt->class.'::'.$elt->getName()); + $Result['listing'] = 'in file '.$elt->file.', class constant '.$Result['link']."$aa"; + break; + case 'page': + $Result['name'] = $elt->getFile(); + $Result['title'] = 'Page'; + $Result['link'] = $this->getPageLink($elt->getFile(), + $elt->package, + $elt->getPath(), + $elt->getFile()); + $Result['listing'] = 'procedural page '.$Result['link']; + break; + case 'include': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Include'; + $Result['link'] = $elt->getValue(); + $Result['listing'] = 'include '.$Result['name']; + break; + } + + return $Result; + } + /** + * Generate alphabetical index of all elements + * + * @see $elements, walk() + */ + function generateElementIndex() + { + $elementindex = array(); + $letters = array(); + $used = array(); + foreach($this->elements as $letter => $nutoh) + { + foreach($this->elements[$letter] as $i => $yuh) + { + if ($this->elements[$letter][$i]->type != 'include') + { + if (!isset($used[$letter])) + { + $letters[]['letter'] = $letter; + $elindex['letter'] = $letter; + $used[$letter] = 1; + } + + $elindex['index'][] = $this->getIndexInformation($this->elements[$letter][$i]); + } + } + if (isset($elindex['index'])) + { + $elementindex[] = $elindex; + } else + { + unset($letters[count($letters) - 1]); + } + $elindex = array(); + } + return array($elementindex,$letters); + } + + function setTemplateDir($dir) + { + Converter::setTemplateDir($dir); + $this->smarty_dir = $this->templateDir; + } + + function copyMediaRecursively($media,$targetdir,$subdir = '') + { + if (!is_array($media)) { + return; + } + foreach($media as $dir => $files) + { + if ($dir === '/') + { + $this->copyMediaRecursively($files,$targetdir); + } else + { + if (!is_numeric($dir)) + { + // create the subdir + phpDocumentor_out("creating $targetdir/$dir\n"); + Converter::setTargetDir($targetdir . PATH_DELIMITER . $dir); + if (!empty($subdir)) $subdir .= PATH_DELIMITER; + $this->copyMediaRecursively($files,"$targetdir/$dir",$subdir . $dir); + } else + { + // copy the file + phpDocumentor_out("copying $targetdir/".$files['file']."\n"); + $this->copyFile($files['file'],$subdir); + } + } + } + } + + /** + * calls the converter setTargetDir, and then copies any template images and the stylesheet if they haven't been copied + * @see Converter::setTargetDir() + */ + function setTargetDir($dir) + { + Converter::setTargetDir($dir); + if ($this->wrote) return; + $this->wrote = true; + $template_images = array(); + $stylesheets = array(); + $tdir = $dir; + $dir = $this->templateDir; + $this->templateDir = $this->templateDir.'templates/'; + $info = new Io; + $this->copyMediaRecursively($info->getDirTree($this->templateDir.'media',$this->templateDir),$tdir); + } + + /** + * Generate alphabetical index of all elements by package and subpackage + * + * @param string $package name of a package + * @see $pkg_elements, walk(), generatePkgElementIndexes() + */ + function generatePkgElementIndex($package) + { +// var_dump($this->pkg_elements[$package]); + $elementindex = array(); + $letters = array(); + $letterind = array(); + $used = array(); + $subp = ''; + foreach($this->pkg_elements[$package] as $subpackage => $els) + { + if (empty($els)) continue; + if (!empty($subpackage)) $subp = " (subpackage: $subpackage)"; else $subp = ''; + foreach($els as $letter => $yuh) + { + foreach($els[$letter] as $i => $yuh) + { + if ($els[$letter][$i]->type != 'include') + { + if (!isset($used[$letter])) + { + $letters[]['letter'] = $letter; + $letterind[$letter] = count($letters) - 1; + $used[$letter] = 1; + } + $elindex[$letter]['letter'] = $letter; + + $elindex[$letter]['index'][] = $this->getIndexInformation($els[$letter][$i]); + } + } + } + } + ksort($elindex); + usort($letters,'CHMdefault_lettersort'); + if (isset($elindex)) + { + while(list($letter,$tempel) = each($elindex)) + { + if (!isset($tempel)) + { + unset($letters[$letterind[$tempel['letter']]]); + } else + $elementindex[] = $tempel; + } + } else $letters = array(); + return array($elementindex,$letters); + } + + /** + * + * @see generatePkgElementIndex() + */ + function generatePkgElementIndexes() + { + $packages = array(); + $package_names = array(); + $pkg = array(); + $letters = array(); + foreach($this->pkg_elements as $package => $trash) + { + $pkgs['package'] = $package; + $pkg['package'] = $package; + list($pkg['pindex'],$letters[$package]) = $this->generatePkgElementIndex($package); + if (count($pkg['pindex'])) + { + $packages[] = $pkg; + $package_names[] = $pkgs; + } + unset($pkgs); + unset($pkg); + } + foreach($packages as $i => $package) + { + $pnames = array(); + for($j=0;$jreturnSee($a, $text, $with_a); + } + + /** + * @param string name of function + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the function's documentation + * @see parent::getFunctionLink() + */ + function getFunctionLink($expr,$package, $file = false,$text = false) + { + $a = Converter::getFunctionLink($expr,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of define + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the define's documentation + * @see parent::getDefineLink() + */ + function getDefineLink($expr,$package, $file = false,$text = false) + { + $a = Converter::getDefineLink($expr,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of global variable + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the global variable's documentation + * @see parent::getGlobalLink() + */ + function getGlobalLink($expr,$package, $file = false,$text = false) + { + $a = Converter::getGlobalLink($expr,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of procedural page + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the procedural page's documentation + * @see parent::getPageLink() + */ + function getPageLink($expr,$package, $path = false,$text = false) + { + $a = Converter::getPageLink($expr,$package,$path); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of method + * @param string class containing method + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the method's documentation + * @see parent::getMethodLink() + */ + function getMethodLink($expr,$class,$package, $file = false,$text = false) + { + $a = Converter::getMethodLink($expr,$class,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of var + * @param string class containing var + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the var's documentation + * @see parent::getVarLink() + */ + function getVarLink($expr,$class,$package, $file = false,$text = false) + { + $a = Converter::getVarLink($expr,$class,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of class constant + * @param string class containing class constant + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the var's documentation + * @see parent::getVarLink() + */ + function getConstLink($expr,$class,$package, $file = false,$text = false) + { + $a = Converter::getConstLink($expr,$class,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * does a nat case sort on the specified second level value of the array + * + * @param mixed $a + * @param mixed $b + * @return int + */ + function rcNatCmp ($a, $b) + { + $aa = strtoupper($a[$this->rcnatcmpkey]); + $bb = strtoupper($b[$this->rcnatcmpkey]); + + return strnatcasecmp($aa, $bb); + } + + /** + * does a nat case sort on the specified second level value of the array. + * this one puts constructors first + * + * @param mixed $a + * @param mixed $b + * @return int + */ + function rcNatCmp1 ($a, $b) + { + $aa = strtoupper($a[$this->rcnatcmpkey]); + $bb = strtoupper($b[$this->rcnatcmpkey]); + + if (strpos($aa,'CONSTRUCTOR') === 0) + { + return -1; + } + if (strpos($bb,'CONSTRUCTOR') === 0) + { + return 1; + } + if (strpos($aa,strtoupper($this->class)) === 0) + { + return -1; + } + if (strpos($bb,strtoupper($this->class)) === 0) + { + return -1; + } + return strnatcasecmp($aa, $bb); + } + + /** + * Write a file to disk, and add it to the {@link $hhp_files} list of files + * to include in the generated CHM + * + * {@source} + */ + function writefile($file,$contents) + { + $this->addHHP($this->targetDir . PATH_DELIMITER . $file); + Converter::writefile($file,$contents); + } + + /** + * @uses $hhp_files creates the array by adding parameter $file + */ + function addHHP($file) + { + $file = str_replace($this->base_dir . PATH_DELIMITER, '', $file); + $file = str_replace('\\',PATH_DELIMITER,$file); + $file = str_replace('//',PATH_DELIMITER,$file); + $file = str_replace(PATH_DELIMITER,'\\',$file); + $this->hhp_files[]['name'] = $file; + } + + function generateTOC() + { + $comppack = ''; + $templ = &$this->newSmarty(); + foreach($this->TOC as $package => $TOC1) + { + $comp_subs = ''; + $comp_subs1 = false; + foreach($TOC1 as $subpackage => $types) + { + $comp_types = ''; + foreach($types as $type => $files) + { + $comp = ''; + $templ1 = &$this->newSmarty(); + $templ1->assign('entry', array()); + foreach($files as $file) + { + // use book icon for classes + if ($type == 'Classes') { + $templ1->append('entry', array('paramname' => $file[0],'outputfile' => $file[1],'isclass' => 1)); + } else { + $templ1->append('entry', array('paramname' => $file[0],'outputfile' => $file[1])); + } + } + $templ = &$this->newSmarty(); + $templ->assign('tocsubentries',$templ1->fetch('tocentry.tpl')); + $templ->assign('entry', array(array('paramname' => $type))); + $comp_types .= $templ->fetch('tocentry.tpl'); + } + if (!empty($subpackage)) + { + $templ = &$this->newSmarty(); + $templ->assign('tocsubentries',$comp_types); + $templ->assign('entry', array(array('paramname' => $subpackage))); + $comp_subs .= $templ->fetch('tocentry.tpl'); + } else + { + $comp_subs1 = $comp_types; + } + } + if ($comp_subs1) + $templ->assign('tocsubentries',$comp_subs1); + if (!empty($comp_subs)) + $templ->assign('entry', array(array('paramname' => $package, 'tocsubentries' => $comp_subs))); + else + $templ->assign('entry', array(array('paramname' => $package))); + $comppack .= $templ->fetch('tocentry.tpl'); + } + return $comppack; + } + + function addSourceTOC($name, $file, $package, $subpackage, $source = false) + { + $file = str_replace($this->base_dir . PATH_DELIMITER, '', $this->targetDir) + . PATH_DELIMITER . $file . '.html'; + $file = str_replace('\\',PATH_DELIMITER,$file); + $file = str_replace('//',PATH_DELIMITER,$file); + $file = str_replace(PATH_DELIMITER,'\\',$file); + $sub = $source ? 'Source Code' : 'Examples'; + $this->TOC[$package][$subpackage][$sub][] = array($name, $file); + } + + function addTOC($name,$file,$package,$subpackage,$class = false,$tutorial = false) + { + $file = str_replace($this->base_dir . PATH_DELIMITER, '', $this->targetDir) + . PATH_DELIMITER . $file . '.html'; + $file = str_replace('\\',PATH_DELIMITER,$file); + $file = str_replace('//',PATH_DELIMITER,$file); + $file = str_replace(PATH_DELIMITER,'\\',$file); + $file = str_replace($this->base_dir . '\\', '', $file); + $sub = $class ? 'Classes' : 'Files'; + if ($tutorial) $sub = 'Manual'; + $this->TOC[$package][$subpackage][$sub][] = array($name,$file); + } + + /** + * Add an item to the index.hhk file + * @param string $name index entry name + * @param string $file filename containing index + * @param string $bookmark html anchor of location in file, if any + * @param string $group group this entry with a string + * @uses $KLinks tracks the index + * @author Andrew Eddie + */ + function addKLink($name, $file, $bookmark='', $group='') + { + $file = $file . '.html'; + $file = str_replace('\\',PATH_DELIMITER,$file); + $file = str_replace('//',PATH_DELIMITER,$file); + $file = str_replace(PATH_DELIMITER,'\\',$file); +// debug("added $name, $file, $bookmark, $group "); + $link = $file; + $link .= $bookmark ? "#$bookmark" :''; + if ($group) { + $this->KLinks[$group]['grouplink'] = $file; + $this->KLinks[$group][] = array($name,$link); + } + $this->KLinks[] = array($name,$link); + } + + /** + * Get the table of contents for index.hhk + * @return string contents of tocentry.tpl generated from $KLinks + * @author Andrew Eddie + */ + function generateKLinks() + { + $templ = &$this->newSmarty(); + $templ->assign('entry', array()); + foreach($this->KLinks as $group=>$link) + { + if (isset($link['grouplink'])) { + $templg = &$this->newSmarty(); + $templg->assign('entry', array()); + foreach($link as $k=>$sublink) + { + if ($k != 'grouplink') { + $templg->append('entry', array('paramname' => $sublink[0],'outputfile' => $sublink[1])); + } + } + $templ->append('entry', array('paramname' => $group, 'outputfile' => $link['grouplink'], 'tocsubentries' => $templg->fetch('tocentry.tpl') )); + } else { + $templ->append('entry', array('paramname' => $link[0],'outputfile' => $link[1])); + } + } + return $templ->fetch('tocentry.tpl'); + } + + /** + * Create the phpdoc.hhp, contents.hhc files needed by MS HTML Help Compiler + * to create a CHM file + * + * The output function generates the table of contents (contents.hhc) + * and file list (phpdoc.hhp) files used to create a .CHM by the + * free MS HTML Help compiler. + * {@internal + * Using {@link $hhp_files}, a list of all separate .html files + * is created in CHM format, and written to phpdoc.hhp. This list was + * generated by {@link writefile}. + * + * Next, a call to the table of contents: + * + * {@source 12 2} + * + * finishes things off}} + * @todo use to directly call html help compiler hhc.exe + * @link http://www.microsoft.com/downloads/release.asp?releaseid=33071 + * @uses generateTOC() assigns to the toc template variable + */ + function Output() + { + $templ = &$this->newSmarty(); + $templ->assign('files',$this->hhp_files); + $this->setTargetDir($this->base_dir); + Converter::writefile('phpdoc.hhp',$templ->fetch('hhp.tpl')); + $templ = &$this->newSmarty(); + $templ->assign('toc',$this->generateTOC()); + Converter::writefile('contents.hhc',$templ->fetch('contents.hhc.tpl')); + $templ->assign('klinks',$this->generateKLinks()); + Converter::writefile('index.hhk',$templ->fetch('index.hhk.tpl')); + phpDocumentor_out("NOTE: to create the documentation.chm file, you must now run Microsoft Help Workshop on phpdoc.hhp\n"); + phpDocumentor_out("To get the free Microsoft Help Workshop, browse to: http://go.microsoft.com/fwlink/?LinkId=14188\n"); + flush(); + } +} + +/** + * @access private + * @global string name of the package to set as the first package + */ +function CHMdefault_pindexcmp($a, $b) +{ + global $phpDocumentor_DefaultPackageName; + if ($a['title'] == $phpDocumentor_DefaultPackageName) return -1; + if ($b['title'] == $phpDocumentor_DefaultPackageName) return 1; + return strnatcasecmp($a['title'],$b['title']); +} + +/** @access private */ +function CHMdefault_lettersort($a, $b) +{ + return strnatcasecmp($a['letter'],$b['letter']); +} + +/** @access private */ +function CHMdefault_outputfilter($src, &$smarty) +{ + return str_replace('{$subdir}',$smarty->_tpl_vars['subdir'],$src); +} +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/options.ini b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/options.ini new file mode 100644 index 00000000..56474470 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/options.ini @@ -0,0 +1,507 @@ +preservedocbooktags = false + +;; used to highlight the {@source} inline tag, @filesource tag, and @example tag +[highlightSourceTokens] +;; format: +;; T_CONSTANTNAME = open +;; /T_CONSTANTNAME = close +T_ABSTRACT = +/T_ABSTRACT = +T_CLONE = +/T_CLONE = +T_HALT_COMPILER = +/T_HALT_COMPILER = +T_PUBLIC = +/T_PUBLIC = +T_PRIVATE = +/T_PRIVATE = +T_PROTECTED = +/T_PROTECTED = +T_FINAL = +/T_FINAL = +T_IMPLEMENTS = +/T_IMPLEMENTS = +T_CLASS = +/T_CLASS = +T_INTERFACE = +/T_INTERFACE = +T_INCLUDE = +/T_INCLUDE = +T_INCLUDE_ONCE = +/T_INCLUDE_ONCE = +T_REQUIRE_ONCE = +/T_REQUIRE_ONCE = +T_FUNCTION = +/T_FUNCTION = +T_VARIABLE = +/T_VARIABLE = +T_CONSTANT_ENCAPSED_STRING = +/T_CONSTANT_ENCAPSED_STRING = +T_COMMENT = +/T_COMMENT = +T_OBJECT_OPERATOR = +/T_OBJECT_OPERATOR = +T_RETURN = +/T_RETURN = +T_STATIC = +/T_STATIC = +T_SWITCH = +/T_SWITCH = +T_IF = +/T_IF = +T_FOREACH = +/T_FOREACH = +T_FOR = +/T_FOR = +T_VAR = +/T_VAR = +T_EXTENDS = +/T_EXTENDS = +T_RETURN = +/T_RETURN = +T_GLOBAL = +/T_GLOBAL = +T_DOUBLE_COLON = +/T_DOUBLE_COLON = +T_OBJECT_OPERATOR = +/T_OBJECT_OPERATOR = +T_OPEN_TAG = +/T_OPEN_TAG = +T_CLOSE_TAG = +/T_CLOSE_TAG = + +[highlightSource] +;; this is for highlighting things that aren't tokens like "&" +;; format: +;; word = open +;; /word = close +@ = +/@ = +& = +/& = +[ = +/[ = +] = +/] = +! = +/! = +";" = +/; = +( = +/( = +) = +/) = +, = +/, = +{ = +/{ = +} = +/} = +""" = +/" = + +[highlightDocBlockSourceTokens] +;; this is for docblock tokens, using by phpDocumentor_HighlightParser +;; tagphptype is for "string" in @param string description, for example +docblock = +/docblock = +tagphptype = +/tagphptype = +tagvarname = +/tagvarname = +coretag = +/coretag = +tag = +/tag = +inlinetag = +/inlinetag = +internal = +/internal = +closetemplate = +/closetemplate = +docblocktemplate = +/docblocktemplate = + +[highlightTutorialSourceTokens] +;; this is for XML DocBook-based tutorials, highlighted by phpDocumentor_TutorialHighlightParser +;; +opentag = +/opentag = +;; +closetag = +/closetag = +;; +attribute = +/attribute = +;; +attributevalue = +/attributevalue = +;; &entity; +entity = +/entity = +;; +comment = +/comment = +;; {@inline tag} +itag = +/itag = + +;; used for translation of html in DocBlocks +[desctranslate] +ul =
          +/ul =
        +ol =
          +/ol =
        +li =
      • +/li =
      • +code =
        +/code = 
        +var = +/var = +samp = +/samp = +kbd = +/kbd = +pre =
        +/pre = 
        +p =

        +/p =

        +b = +/b = +i = +/i = +br =
        + +[ppage] +;; this is the DocBook package page translation section. All DocBook tags +;; that have a corresponding html tag must be listed here +;; +;; examples: +;; 1) +;; tagname = newtagname +;; +;; This is the simplest case, where all attributes will be added into the +;; starting tag and the ending tag will be html/xml style +;; becomes and +;; becomes +;; +;; +;; 2) +;; tagname = newtagname +;; tagname->attr = newattrname +;; +;; in this case, everything will be like the first case, except tags like: +;; will become +;; +;; +;; 3) +;; tagname = newtagname +;; tagname->attr = newattrname +;; tagname->attr+value = newvalue +;; +;; in this case, the value is also translated to another. This can be useful +;; for instances such as focus="middle" changing to align="center" or something +;; of that nature. +;; will become +;; +;; +;; 4) +;; tagname = newtagname +;; tagname->attr1 = newattrname +;; tagname->attr2 = newattrname +;; tagname->attr1+value|attr2+value = newvalue +;; +;; in this case, two attributes combine to make one new attribute, and the combined +;; value is translated into a new value +;; will become +;; +;; +;; 5) +;; tagname = newtagname +;; tagname!attr = dummy +;; +;; here, the attribute will be ignored. dummy is not used and may be any value +;; will become +;; +;; +;; 6) +;; tagname = newtagname +;; tagname! = dummy +;; +;; here, all attributes will be ignored. dummy is not used and may be any value +;; will become +;; +;; +;; 7) +;; tagname = newtagname +;; tagname/ = 1 +;; +;; here, the tag will be translated as a single tag with no closing tag, and all +;; attributes +;; {text text} will become +;; +;; +;; 8) +;; tagname = +;; /tagname = closetagtext +;; +;; in this case, the text will be inserted exactly as entered for +;; and closetagtext for +;; will become +;; closetagtext +;; +;; 9) +;; $attr$my_attribute = newattrname +;; +;; tagname = newtagname +;; +;; in this case, all occurences of my_attribute in any tag will be changed to +;; newattrname. This is useful for changing things like role="php" to +;; class="php," for example. Note that the text "$attr$" MUST be on the line +;; start for phpDocumentor to recognize it. +;; +;; 10) +;; &entity; = translation text +;; " = " +;; " = """ +;; < = < +;; +;; Use this to control translation of entities to their appropriate values + +  =   +" = " +” = ” +“ = “ +& = & +< = < +> = > +© = © + +$attr$role = class + +abbrev = abbr + +blockquote = blockquote + +arg = span +arg->choice = class + +author = by +/author = +author! = 0 + +authorblurb = blockquote + +authorgroup = Authors:
        +/authorgroup = +authorgroup! = 0 + +caution =
        Caution
        +/caution =
        +caution! = 0 + +command = +/command = + +cmdsynopsis =
        +/cmdsynopsis =
        + +copyright = +/copyright =
        + +emphasis = strong + +example =
        +/example =
        +example! = 0 + +function = +/function = () + +formalpara = p + +graphic = img +graphic->fileref = src +graphic/ = + +important = u + +informalequation = blockquote + +informalexample = pre + +inlineequation = em + +itemizedlist = ul + +listitem = li + +literal = code + +literallayout = pre + +option = " " +/option = + +orderedlist = ol + +para = p + +programlisting =
        +/programlisting = 
        +programlisting! = 0 + +refentry = div + +refnamediv =
        +/refnamediv =
        +refnamediv! = 0 + +refname = h1 + +refpurpose =

        +/refpurpose =

        + +refsynopsisdiv =
        +/refsynopsisdiv =
        +refsynopsisdiv! = 0 + +refsect1 = span + +refsect2 = +/refsect2 =
        + +refsect3 = +/refsect3 =
        + +releaseinfo = ( +/releaseinfo = )
        + +simpara = +/simpara =
        +simpara! = 0 + +subscript = sub + +superscript = super + +table = table + +table->colsep = rules +table->rowsep = rules +table->colsep+1|rowsep+1 = all +table->colsep+1|rowsep+0 = cols +table->colsep+0|rowsep+1 = rows + +table->frame = frame +table->frame+all = border +table->frame+none = void +table->frame+sides = vsides +table->frame+top = above +table->frame+topbot = hsides + +thead = thead + +tfoot = tfoot + +tbody = tbody + +colspec = col + +tgroup = colgroup +tgroup/ = 1 +tgroup->cols = span + +row = tr + +entry = td +entry->morerows = colspan +entry->morerows+1 = 2 +entry->morerows+2 = 3 +entry->morerows+3 = 4 +entry->morerows+4 = 5 +entry->morerows+5 = 6 +entry->morerows+6 = 7 +entry->morerows+7 = 8 +entry->morerows+8 = 9 +entry->morerows+9 = 10 +entry->morerows+10 = 11 +;; add more if you need more colspans + +warning =
        +/warning =
        +warning! = 0 + +;; now begins the attributes that should be tags in cdata +[$attr$id] +open = a +;close = /a +cdata! = true +quotevalues = true +separator = "=" +;separateall = true +$id = name + +;; now begins the sections that deal with +[refsynopsisdiv_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <h1 class="title" align="center"> +close = </h1> + +[refsect1_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <h2 class="title" align="center"> +close = </h1> + +[refsect2_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <h2 class="title" align="center"> +close = </h2> + +[refsect3_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <h3 class="title" align="center"> +close = </h3> + +[para_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <strong class="title" align="center"> +close = </strong> + +[formalpara_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <strong class="title" align="center"> +close = </strong> + +[example_title] +;tag_attr = true +;attr_name = title +;cdata_start = true +cdata_end = true +open = </td></tr><tr><td><strong> +close = </strong> + +[table_title] +;tag_attr = true +;attr_name = true +cdata_start = true +open = <caption> +close = </caption> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/basicindex.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/basicindex.tpl new file mode 100644 index 00000000..a040830b --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/basicindex.tpl @@ -0,0 +1,21 @@ +{section name=letter loop=$letters} + <a href="{$indexname}.html#{$letters[letter].letter}">{$letters[letter].letter}</a> +{/section} +<table> +{section name=index loop=$index} +<tr><td colspan = "2"><a name="{$index[index].letter}">  </a> +<a href="#top">top</a><br> +<TABLE CELLPADDING='3' CELLSPACING='0' WIDTH='100%' CLASS="border"> + <TR CLASS='TableHeadingColor'> + <TD> + <FONT SIZE='+2'><B>{$index[index].letter}</B></FONT> + </TD> + </TR> +</TABLE> +</td></tr> + {section name=contents loop=$index[index].index} + <tr><td><b>{$index[index].index[contents].name}</b></td><td width="100%" align="left" valign="top">{$index[index].index[contents].listing}</td></tr> + {/section} +{/section} +</table> + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/blank.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/blank.tpl new file mode 100644 index 00000000..1fbaca2f --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/blank.tpl @@ -0,0 +1,13 @@ +<html> +<head> + <title>{$maintitle} + + + + +

        {$maintitle}

        +Welcome to {$package}!
        +
        +This documentation was generated by phpDocumentor v{$phpdocversion}
        + + \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/class.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/class.tpl new file mode 100644 index 00000000..1ed17562 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/class.tpl @@ -0,0 +1,94 @@ +{include file="header.tpl" eltype="class" hasel=true contents=$classcontents} + +

        + {if $is_interface}Interface{else}Class{/if} {$class_name} +
        +

        +[line {if $class_slink}{$class_slink}{else}{$line_number}{/if}]
        +
        +{section name=tree loop=$class_tree.classes}{$class_tree.classes[tree]}{$class_tree.distance[tree]}{/section}
        +
        +{if $tutorial} +
        Class Tutorial: {$tutorial}
        +{/if} +{if $children} +Classes extended from {$class_name}: + {section name=kids loop=$children} +
        +
        {$children[kids].link}
        +
        {$children[kids].sdesc}
        +
        + {/section}

        +{/if} +{if $conflicts.conflict_type}

        Conflicts with classes:
        + {section name=me loop=$conflicts.conflicts} + {$conflicts.conflicts[me]}
        + {/section} +

        +{/if} +Location: {$source_location} +


        +{include file="docblock.tpl" type="class" sdesc=$sdesc desc=$desc} +
        +{include file="var.tpl" show="summary"} +
        +{include file="const.tpl" show="summary"} +
        + + +

        Inherited Class Constant Summary

        + +{section name=iconsts loop=$iconsts} +

        Inherited From Class {$iconsts[iconsts].parent_class}

        +
          + {section name=iconsts2 loop=$iconsts[iconsts].iconsts} + +
        • {$iconsts[iconsts].iconsts[iconsts2].link} = {$iconsts[iconsts].iconsts[iconsts2].value} +
          + {$iconsts[iconsts].iconsts[iconsts2].sdesc} + {/section} +
        • +
        +{/section} +
        + + +

        Inherited Class Variable Summary

        + +{section name=ivars loop=$ivars} +

        Inherited From Class {$ivars[ivars].parent_class}

        +
          + {section name=ivars2 loop=$ivars[ivars].ivars} + +
        • {$ivars[ivars].ivars[ivars2].link} = {$ivars[ivars].ivars[ivars2].default} +
          + {$ivars[ivars].ivars[ivars2].sdesc} + {/section} +
        • +
        +{/section} + +
        +{include file="method.tpl" show="summary"} + + +

        Inherited Method Summary

        + +{section name=imethods loop=$imethods} +

        Inherited From Class {$imethods[imethods].parent_class}

        +
          + {section name=im2 loop=$imethods[imethods].imethods} + +
        • {$imethods[imethods].imethods[im2].link}
          + {$imethods[imethods].imethods[im2].sdesc} + {/section} +
        +{/section} +
        +{include file="method.tpl"} +
        +{include file="var.tpl"} +
        +{include file="const.tpl"} +
        +{include file="footer.tpl"} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/classleft.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/classleft.tpl new file mode 100644 index 00000000..15bf6b7e --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/classleft.tpl @@ -0,0 +1,8 @@ +{foreach key=subpackage item=files from=$classleftindex} + {if $subpackage != ""}{$subpackage}
        {/if} + {section name=files loop=$files} + {if $files[files].link != ''}{/if} + {$files[files].title} + {if $files[files].link != ''}{/if}
        + {/section} +{/foreach} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/classtrees.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/classtrees.tpl new file mode 100644 index 00000000..28c648be --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/classtrees.tpl @@ -0,0 +1,12 @@ +{capture name="title"}Class Trees for Package {$package}{/capture} +{include file="header.tpl" title=$smarty.capture.title} + + +

        + {$smarty.capture.title} +

        +{section name=classtrees loop=$classtrees} +Root class {$classtrees[classtrees].class} +{$classtrees[classtrees].class_tree} +{/section} +{include file="footer.tpl"} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/const.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/const.tpl new file mode 100644 index 00000000..207491a5 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/const.tpl @@ -0,0 +1,29 @@ +{if $show=="summary"} + + +

        Class Constant Summary

        + +
          + {section name=consts loop=$consts} + +
        • {$consts[consts].const_name} = {$consts[consts].const_value|replace:"\n":"
          \n"|replace:" ":" "|replace:"\t":"   "}
          +
          + {$consts[consts].sdesc} + {/section} +
        +{else} + + + + +

        Class Constant Detail

        + +
          +{section name=consts loop=$consts} + +
        • {$consts[consts].const_name} = {$consts[consts].const_value|replace:"\n":"
          \n"|replace:" ":" "|replace:"\t":"   "}
          [line {if $consts[consts].slink}{$consts[consts].slink}{else}{$consts[consts].line_number}{/if}]
        • +{include file="docblock.tpl" sdesc=$consts[consts].sdesc desc=$consts[consts].desc tags=$consts[consts].tags} +
          +{/section} +
        +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/contents.hhc.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/contents.hhc.tpl new file mode 100644 index 00000000..cf7ee7cb --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/contents.hhc.tpl @@ -0,0 +1,11 @@ + + + + + + + + + +{$toc} + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/define.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/define.tpl new file mode 100644 index 00000000..3917cc70 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/define.tpl @@ -0,0 +1,33 @@ +{if $summary} + + +

        Constant Summary

        + +
          + {section name=def loop=$defines} +
        • {$defines[def].define_name} = {$defines[def].define_value} +
          {$defines[def].sdesc} + {/section} +
        +{else} + + + +

        Constant Detail

        + +
          + {section name=def loop=$defines} + +
        • {$defines[def].define_name} = {$defines[def].define_value} [line {if $defines[def].slink}{$defines[def].slink}{else}{$defines[def].line_number}{/if}]
          + {if $defines[def].define_conflicts.conflict_type} +

          Conflicts with defines: + {section name=me loop=$defines[def].define_conflicts.conflicts} + {$defines[def].define_conflicts.conflicts[me]}
          + {/section} +

          + {/if} +

          + {include file="docblock.tpl" sdesc=$defines[def].sdesc desc=$defines[def].desc tags=$defines[def].tags} + {/section} +
        +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/docblock.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/docblock.tpl new file mode 100644 index 00000000..0de18b67 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/docblock.tpl @@ -0,0 +1,31 @@ + +{if $function} + {if $params} +

        Parameters

        + {section name=params loop=$params} +

        {$params[params].var}

        +

        {$params[params].data}

        + {/section} + {/if} +{/if} +{section name=tags loop=$tags} +{if $tags[tags].keyword == 'return'} +

        Returns

        +

        {$tags[tags].data}

        +{/if} +{/section} +{if $sdesc || $desc} +

        Remarks

        +{/if} +{if $sdesc} +

        {$sdesc}

        +{/if} +{if $desc} +

        {$desc}

        +{/if} +{section name=tags loop=$tags} +{if $tags[tags].keyword != 'return'} +

        {$tags[tags].keyword}

        +

        {$tags[tags].data}

        +{/if} +{/section} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/elementindex.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/elementindex.tpl new file mode 100644 index 00000000..8e25db5c --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/elementindex.tpl @@ -0,0 +1,9 @@ +{include file="header.tpl" noleftindex=true} + +

        Index of All Elements

        +Indexes by package:
        +{section name=p loop=$packageindex} +{$packageindex[p].title}
        +{/section}
        +{include file="basicindex.tpl" indexname="elementindex"} +{include file="footer.tpl"} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/errors.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/errors.tpl new file mode 100644 index 00000000..1576a822 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/errors.tpl @@ -0,0 +1,21 @@ +{include file="header.tpl" noleftindex=true} +{section name=files loop=$files} +{$files[files].file}
        +{/section} +{foreach key=file item=issues from=$all} + +

        {$file}

        +{if count($issues.warnings)} +

        Warnings:


        +{section name=warnings loop=$issues.warnings} +{$issues.warnings[warnings].name} - {$issues.warnings[warnings].listing}
        +{/section} +{/if} +{if count($issues.errors)} +

        Errors:


        +{section name=errors loop=$issues.errors} +{$issues.errors[errors].name} - {$issues.errors[errors].listing}
        +{/section} +{/if} +{/foreach} +{include file="footer.tpl"} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/fileleft.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/fileleft.tpl new file mode 100644 index 00000000..c85acbe0 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/fileleft.tpl @@ -0,0 +1,8 @@ +{foreach key=subpackage item=files from=$fileleftindex} + {if $subpackage != ""}subpackage {$subpackage}
        {/if} + {section name=files loop=$files} + {if $files[files].link != ''}{/if} + {$files[files].title} + {if $files[files].link != ''}{/if}
        + {/section} +{/foreach} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/filesource.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/filesource.tpl new file mode 100644 index 00000000..a0d7119e --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/filesource.tpl @@ -0,0 +1,6 @@ +{capture name="tutle"}File Source for {$name}{/capture} +{include file="header.tpl" title=$smarty.capture.tutle} +

        Source for file {$name}

        +

        Documentation is available at {$docs}

        +{$source} +{include file="footer.tpl"} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/footer.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/footer.tpl new file mode 100644 index 00000000..a015ceea --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/footer.tpl @@ -0,0 +1,8 @@ +{if !$index} +
        +
        + Documentation generated on {$date} by phpDocumentor {$phpdocversion} +
        +{/if} + + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/function.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/function.tpl new file mode 100644 index 00000000..ea314935 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/function.tpl @@ -0,0 +1,44 @@ +{if $summary} + + +

        Function Summary

        + + +{else} + + + +

        Function Detail

        + +
          +{section name=func loop=$functions} + + +
        • {$functions[func].function_return} {$functions[func].function_name}() [line {if $functions[func].slink}{$functions[func].slink}{else}{$functions[func].line_number}{/if}]
          +

          +Usage: {if $functions[func].ifunction_call.returnsref}&{/if}{$functions[func].function_name}( +{if count($functions[func].ifunction_call.params)} +{section name=params loop=$functions[func].ifunction_call.params} +{if $smarty.section.params.iteration != 1}, {/if}{if $functions[func].ifunction_call.params[params].default != ''}[{/if}{$functions[func].ifunction_call.params[params].type} {$functions[func].ifunction_call.params[params].name}{if $functions[func].ifunction_call.params[params].default != ''} = {$functions[func].ifunction_call.params[params].default|escape:"html"}]{/if} +{/section} +{/if}) +

          +{if $functions[func].function_conflicts.conflict_type} +

          Conflicts with functions: +{section name=me loop=$functions[func].function_conflicts.conflicts} +{$functions[func].function_conflicts.conflicts[me]}
          +{/section} +

          +{/if} +{include file="docblock.tpl" sdesc=$functions[func].sdesc desc=$functions[func].desc tags=$functions[func].tags params=$functions[func].params function=true} +
          +

          [ Top ]

          +{/section} +
        +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/global.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/global.tpl new file mode 100644 index 00000000..c1b74a1c --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/global.tpl @@ -0,0 +1,32 @@ +{if $summary} + + +

        Global Variable Summary

        + + + +{else} + + + +

        Global Variable Detail

        + +
          + {section name=glob loop=$globals} + +
        • {$globals[glob].global_type} {$globals[glob].global_name} = {$globals[glob].global_value} [line {if $globals[glob].slink}{$globals[glob].slink}{else}{$globals[glob].line_number}{/if}]
          + {if $globals[glob].global_conflicts.conflict_type} +

          Conflicts with globals: + {section name=me loop=$globals[glob].global_conflicts.conflicts} + {$globals[glob].global_conflicts.conflicts[me]}
          + {/section} + {/if}

          + {include file="docblock.tpl" sdesc=$globals[glob].sdesc desc=$globals[glob].desc tags=$globals[glob].tags} + {/section} +

        +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/header.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/header.tpl new file mode 100644 index 00000000..bdf6173e --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/header.tpl @@ -0,0 +1,22 @@ + + + + + + + {$title} + +{if $bgleft} + +{/if} + + + \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/hhp.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/hhp.tpl new file mode 100644 index 00000000..a68f02b1 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/hhp.tpl @@ -0,0 +1,17 @@ +[OPTIONS] +Compatibility=1.1 or later +Compiled file=documentation.chm +Contents file=contents.hhc +Default topic=index.html +Display compile progress=No +Index file=Index.hhk +Language=0x409 English (United States) + + +[FILES] +{section name=files loop=$files} +{$files[files].name} +{/section} + +[INFOTYPES] + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/include.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/include.tpl new file mode 100644 index 00000000..1ab7440b --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/include.tpl @@ -0,0 +1,26 @@ +{if $summary} + + +

        Include Statements Summary

        + + +{else} + + + +

        Include Statements Detail

        + +
          + {section name=includes loop=$includes} + +
        • {$includes[includes].include_name} file: = {$includes[includes].include_value} [line {if $includes[includes].slink}{$includes[includes].slink}{else}{$includes[includes].line_number}{/if}]
          +

          + {include file="docblock.tpl" sdesc=$includes[includes].sdesc desc=$includes[includes].desc tags=$includes[includes].tags} + {/section} +
        +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/index.hhk.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/index.hhk.tpl new file mode 100644 index 00000000..8b31a11d --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/index.hhk.tpl @@ -0,0 +1,8 @@ + + + + + + +{$klinks} + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/index.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/index.tpl new file mode 100644 index 00000000..f73fb8a3 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/index.tpl @@ -0,0 +1,24 @@ + + + + + + {$title} + + +{if $package_count > 1} + + +{/if} + +{if $package_count > 1} + +{/if} + + + <H2>Frame Alert</H2> + <P>This document is designed to be viewed using the frames feature. + If you see this message, you are using a non-frame-capable web client.</P> + + + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/media/bg_left.png b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/media/bg_left.png new file mode 100644 index 00000000..19fdf05d Binary files /dev/null and b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/media/bg_left.png differ diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/media/stylesheet.css b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/media/stylesheet.css new file mode 100644 index 00000000..2c08f94f --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/media/stylesheet.css @@ -0,0 +1,129 @@ +BODY, DIV, SPAN, PRE, CODE, TD, TH { + line-height: 140%; + font-size: 10pt; + font-family: verdana,arial,sans-serif; +} + +H1 { + font-size: 12pt; +} + +H4 { + font-size: 10pt; + font-weight: bold; +} + +P.label { + margin-bottom: 5px; +} +P.dt { + margin-top: 0px; + margin-bottom: 0px; +} +P.indent { + margin-top: 0px; + margin-left: 20px; + margin-bottom: 0px; +} +P.method { + background-color: #f0f0f0; + padding: 2px; + border: 1px #cccccc solid; +} + +A { + text-decoration: none; +} + +A:link{ + color: #336699; +} + +A:visited { + color: #003366; +} + +A:active, A:hover { + color: #6699CC; +} + +A:hover{ + text-decoration: underline; +} + +SPAN.type { + color: #336699; + font-size: xx-small; + font-weight: normal; + } + +PRE { + background-color: #EEEEEE; + padding: 10px; + border-width: 1px; + border-color: #336699; + border-style: solid; +} + +HR { + color: #336699; + background-color: #336699; + border-width: 0px; + height: 1px; + filter: Alpha (opacity=100,finishopacity=0,style=1); +} + +DIV.sdesc { + font-weight: bold; + background-color: #EEEEEE; + padding: 10px; + border-width: 1px; + border-color: #336699; + border-style: solid; +} + +DIV.desc { + font-family: monospace; + background-color: #EEEEEE; + padding: 10px; + border-width: 1px; + border-color: #336699; + border-style: solid; +} + +SPAN.code { + font-family: monospace; +} + +CODE.varsummarydefault{ + padding: 1px; + border-width: 1px; + border-style: dashed; + border-color: #336699; +} + +UL.tute { + margin: 0px; + padding: 0px; + padding-left: 5px; + } + +LI.tute { + line-height: 140%; + font-size: 10pt; + text-indent: -15px; + padding-bottom: 2px; + padding-left: 14px; +} + +.small{ + font-size: 9pt; +} + + +.tute-tag { color: #009999 } +.tute-attribute-name { color: #0000FF } +.tute-attribute-value { color: #0099FF } +.tute-entity { font-weight: bold; } +.tute-comment { font-style: italic } +.tute-inline-tag { color: #636311; font-weight: bold } diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/method.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/method.tpl new file mode 100644 index 00000000..9309962b --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/method.tpl @@ -0,0 +1,55 @@ +{if $show == 'summary'} + + +

        Method Summary

        + + + +{else} + + + +

        Method Detail

        + +
          +{section name=methods loop=$methods} + + +

          {$class_name}::{$methods[methods].function_name}

          + +

          +{if $methods[methods].ifunction_call.returnsref}&{/if}{$methods[methods].function_name}( +{if count($methods[methods].ifunction_call.params)} +{section name=params loop=$methods[methods].ifunction_call.params} +{if $smarty.section.params.iteration != 1}, {/if} +{if $methods[methods].ifunction_call.params[params].default != ''}[{/if}{$methods[methods].ifunction_call.params[params].type} +{$methods[methods].ifunction_call.params[params].name}{if $methods[methods].ifunction_call.params[params].default != ''} = {$methods[methods].ifunction_call.params[params].default}]{/if} +{/section} +{/if} ); +

          + +{if $methods[methods].descmethod} +

          Overridden in child classes as:
          + {section name=dm loop=$methods[methods].descmethod} +

          +
          {$methods[methods].descmethod[dm].link}
          +
          {$methods[methods].descmethod[dm].sdesc}
          +
          + {/section}

          +{/if} +{if $methods[methods].method_overrides} +

          Overrides {$methods[methods].method_overrides.link} ({$methods[methods].method_overrides.sdesc|default:"parent method not documented"})

          +{/if} + +{include file="docblock.tpl" sdesc=$methods[methods].sdesc desc=$methods[methods].desc tags=$methods[methods].tags params=$methods[methods].params function=true} +

          [ Top ]

          +
          +{/section} +
        +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/packages.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/packages.tpl new file mode 100644 index 00000000..b48b6719 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/packages.tpl @@ -0,0 +1,3 @@ +{section name=packages loop=$packages} +{$packages[packages].title} +{/section} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/page.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/page.tpl new file mode 100644 index 00000000..dc93b0a1 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/page.tpl @@ -0,0 +1,34 @@ +{include file="header.tpl" eltype="Procedural file"} +

        File: {$source_location}
        +

        +{if $tutorial} +
        Main Tutorial: {$tutorial}
        +{/if} +{include file="docblock.tpl" desc=$desc sdesc=$sdesc tags=$tags} +Classes in this file: +
        +{section name=classes loop=$classes} +
        {$classes[classes].link}
        +
        {$classes[classes].sdesc}
        +{/section} +
        +
        +{include file="include.tpl" summary=true} +
        +{include file="global.tpl" summary=true} +
        +{include file="define.tpl" summary=true} +
        +{include file="function.tpl" summary=true} +
        +{include file="include.tpl"} +
        +{include file="global.tpl"} +
        +{include file="define.tpl"} +
        +{include file="function.tpl"} +
        +{include file="footer.tpl"} + + \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/pkgelementindex.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/pkgelementindex.tpl new file mode 100644 index 00000000..68897450 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/pkgelementindex.tpl @@ -0,0 +1,14 @@ +{include file="header.tpl"} + +

        Element index for package {$package}

        +{if count($packageindex) > 1} +Indexes by package:
        +{/if} +{section name=p loop=$packageindex} +{if $packageindex[p].title != $package} +{$packageindex[p].title}
        +{/if} +{/section}
        +Index of all elements
        +{include file="basicindex.tpl" indexname=elementindex_$package} +{include file="footer.tpl"} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/ric.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/ric.tpl new file mode 100644 index 00000000..c4cb83f9 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/ric.tpl @@ -0,0 +1,6 @@ +{include file="header.tpl"} +

        {$name}

        +
        +{$contents|htmlentities}
        +
        +{include file="footer.tpl"} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/tocentry.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/tocentry.tpl new file mode 100644 index 00000000..87f68ebb --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/tocentry.tpl @@ -0,0 +1,11 @@ +
          +{section name=entry loop=$entry} +
        • + +{if $entry[entry].isclass} +{/if}{if $entry[entry].outputfile} +{/if} + {if $entry[entry].tocsubentries}{$entry[entry].tocsubentries}{/if} +{/section} + {$tocsubentries} +
        diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/todolist.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/todolist.tpl new file mode 100644 index 00000000..5ab0bca2 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/todolist.tpl @@ -0,0 +1,14 @@ +{include file="header.tpl" title="Todo List"} +

        Todo List

        +{foreach from=$todos key=todopackage item=todo} +

        {$todopackage}

        +{section name=todo loop=$todo} +

        {$todo[todo].link}

        +
          +{section name=t loop=$todo[todo].todos} +
        • {$todo[todo].todos[t]}
        • +{/section} +
        +{/section} +{/foreach} +{include file="footer.tpl"} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/tutorial.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/tutorial.tpl new file mode 100644 index 00000000..22c71c3b --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/tutorial.tpl @@ -0,0 +1,32 @@ +{include file="header.tpl" title=$title} +{if $nav} + + + + + + +
        {if $prev}{/if}Prev{if $prev}{/if}{if $next}{/if}Next{if $next}{/if}
        +{/if} +{$contents} +{if $nav} + + + + + + + + + + + + +
        {if $prev}{/if} +Prev{if $prev}{/if}{if $up}Up{else} {/if}{if $next}{/if}Next{if $next}{/if}
        {if $prevtitle}{$prevtitle}{/if}{if $uptitle}{$uptitle}{/if}{if $nexttitle}{$nexttitle}{/if}
        +{/if} +{include file="footer.tpl"} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/tutorial_toc.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/tutorial_toc.tpl new file mode 100644 index 00000000..1db34438 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/tutorial_toc.tpl @@ -0,0 +1,29 @@ +{if count($toc)} +

        Table of Contents

        +
          +{section name=toc loop=$toc} +{if $toc[toc].tagname == 'refsect1'} +{assign var="context" value="refsect1"} +{$toc[toc].link}
          +{/if} +{if $toc[toc].tagname == 'refsect2'} +{assign var="context" value="refsect2"} +   {$toc[toc].link}
          +{/if} +{if $toc[toc].tagname == 'refsect3'} +{assign var="context" value="refsect3"} +      {$toc[toc].link}
          +{/if} +{if $toc[toc].tagname == 'table'} +{if $context == 'refsect2'}   {/if} +{if $context == 'refsect3'}   {/if} +Table: {$toc[toc].link} +{/if} +{if $toc[toc].tagname == 'example'} +{if $context == 'refsect2'}   {/if} +{if $context == 'refsect3'}   {/if} +Table: {$toc[toc].link} +{/if} +{/section} +
        +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/tutorial_tree.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/tutorial_tree.tpl new file mode 100644 index 00000000..6997545a --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/tutorial_tree.tpl @@ -0,0 +1,5 @@ + + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/var.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/var.tpl new file mode 100644 index 00000000..d6f04b53 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/var.tpl @@ -0,0 +1,30 @@ +{if $show=="summary"} + + +

        Class Variable Summary

        + +
          + {section name=vars loop=$vars} + +
        • {$vars[vars].var_name} = {$vars[vars].var_default|replace:"\n":"
          \n"|replace:" ":" "|replace:"\t":"   "}
          +
          + {$vars[vars].sdesc} + {/section} +
        +{else} + + + + +

        Variable Detail

        + +
          +{section name=vars loop=$vars} + +
        • {$vars[vars].var_name} = {$vars[vars].var_default|replace:"\n":"
          \n"|replace:" ":" "|replace:"\t":"   "}
          [line {if $vars[vars].slink}{$vars[vars].slink}{else}{$vars[vars].line_number}{/if}]
        • +
        • Data type: {$vars[vars].var_type}{if $vars[vars].var_overrides}Overrides: {$vars[vars].var_overrides}
          {/if}
        • +{include file="docblock.tpl" sdesc=$vars[vars].sdesc desc=$vars[vars].desc tags=$vars[vars].tags} +
          +{/section} +
        +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/HTMLSmartyConverter.inc b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/HTMLSmartyConverter.inc new file mode 100644 index 00000000..09f5af73 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/HTMLSmartyConverter.inc @@ -0,0 +1,1779 @@ + + * @since 1.0rc1 + * @version $Revision: 1.1 $ + */ +/** + * HTML output converter. + * This Converter takes output from the {@link Parser} and converts it to HTML-ready output for use with {@link Smarty}. + * + * @package Converters + * @subpackage HTMLSmarty + * @see parserDocBlock, parserInclude, parserPage, parserClass, parserDefine, parserFunction, parserMethod, parserVar + * @author Greg Beaver + * @since 1.0rc1 + * @version $Revision: 1.1 $ + */ +class HTMLSmartyConverter extends Converter +{ + /** + * Smarty Converter wants elements sorted by type as well as alphabetically + * @see Converter::$sort_page_contents_by_type + * @var boolean + */ + var $sort_page_contents_by_type = true; + /** @var string */ + var $outputformat = 'HTML'; + /** @var string */ + var $name = 'Smarty'; + /** + * indexes of elements by package that need to be generated + * @var array + */ + var $leftindex = array('classes' => true, 'pages' => true, 'functions' => true, 'defines' => false, 'globals' => false); + + /** + * output directory for the current procedural page being processed + * @var string + */ + var $page_dir; + + /** + * target directory passed on the command-line. + * {@link $targetDir} is malleable, always adding package/ and package/subpackage/ subdirectories onto it. + * @var string + */ + var $base_dir; + + /** + * output directory for the current class being processed + * @var string + */ + var $class_dir; + + /** + * array of converted package page names. + * Used to link to the package page in the left index + * @var array Format: array(package => 1) + */ + var $package_pages = array(); + + /** + * controls formatting of parser informative output + * + * Converter prints: + * "Converting /path/to/file.php... Procedural Page Elements... Classes..." + * Since HTMLdefaultConverter outputs files while converting, it needs to send a \n to start a new line. However, if there + * is more than one class, output is messy, with multiple \n's just between class file output. This variable prevents that + * and is purely cosmetic + * @var boolean + */ + var $juststarted = false; + + /** + * contains all of the template procedural page element loop data needed for the current template + * @var array + */ + var $current; + + /** + * contains all of the template class element loop data needed for the current template + * @var array + */ + var $currentclass; + var $wrote = false; + var $ric_set = array(); + + /** + * sets {@link $base_dir} to $targetDir + * @see Converter() + */ + + /**#@+ + * @access private + */ + var $_classleft_cache = false; + var $_classcontents_cache = false; + var $_pagecontents_cache = false; + var $_pageleft_cache = false; + var $_done_package_index = false; + var $_ric_done = false; + var $_wrote_tdir = false; + var $ric_contents = array(); + /**#@-*/ + + function HTMLSmartyConverter(&$allp, &$packp, &$classes, &$procpages, $po, $pp, $qm, $targetDir, $templateDir, $title) + { + Converter::Converter($allp, $packp, $classes, $procpages,$po, $pp, $qm, $targetDir, $templateDir, $title); + $this->base_dir = $targetDir; + } + + function writeSource($path, $value) + { + $templ = &$this->newSmarty(); + $pathinfo = $this->proceduralpages->getPathInfo($path, $this); + $templ->assign('source',$value); + $templ->assign('package',$pathinfo['package']); + $templ->assign('subpackage',$pathinfo['subpackage']); + $templ->assign('name',$pathinfo['name']); + $templ->assign('source_loc',$pathinfo['source_loc']); + $templ->assign('docs',$pathinfo['docs']); + $templ->assign("subdir",'../'); + $templ->register_outputfilter('HTMLSmarty_outputfilter'); + $this->setTargetDir($this->getFileSourcePath($this->base_dir)); + phpDocumentor_out("\n"); + $this->setSourcePaths($path); + $this->writefile($this->getFileSourceName($path).'.html',$templ->fetch('filesource.tpl')); + } + + function writeExample($title, $path, $source) + { + $templ = &$this->newSmarty(); + $templ->assign('source',$source); + if (empty($title)) + { + $title = 'example'; + addWarning(PDERROR_EMPTY_EXAMPLE_TITLE, $path, $title); + } + $templ->assign('title',$title); + $templ->assign('file',$path); + $templ->assign("subdir",'../'); + $templ->register_outputfilter('HTMLSmarty_outputfilter'); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . '__examplesource'); + phpDocumentor_out("\n"); + $this->writefile('exsource_'.$path.'.html',$templ->fetch('examplesource.tpl')); + } + + function getExampleLink($path, $title) + { + return $this->returnLink('{$subdir}__examplesource' . PATH_DELIMITER . 'exsource_'.$path.'.html',$title); + } + + function getSourceLink($path) + { + return $this->returnLink($this->getFileSourcePath('{$subdir}') . + PATH_DELIMITER . $this->getFileSourceName($path).'.html','Source Code for this file'); + } + + /** + * Return a line of highlighted source code with formatted line number + * + * If the $path is a full path, then an anchor to the line number will be + * added as well + * @param integer line number + * @param string highlighted source code line + * @param false|string full path to @filesource file this line is a part of, + * if this is a single line from a complete file. + * @return string formatted source code line with line number + */ + function sourceLine($linenumber, $line, $path = false) + { + $extra = ''; + if (strlen(str_replace("\n", '', $line)) == 0) { + $extra = ' '; + } + if ($path) + { + return '
      • ' . $this->getSourceAnchor($path, $linenumber) . + str_replace("\n",'',$line) . $extra . + "
      • \n"; + } else + { + return '
      • ' . str_replace("\n",'',$line) . "$extra
      • \n"; + } + } + + /** + * Used to convert the <> tag in a docblock + * @param string + * @param boolean + * @return string + */ + function ProgramExample($example, $tutorial = false, $inlinesourceparse = null/*false*/, + $class = null/*false*/, $linenum = null/*false*/, $filesourcepath = null/*false*/) + { + $trans = $this->template_options['desctranslate']; + $this->template_options['desctranslate'] = array(); + $example = '
          ' . parent::ProgramExample($example, $tutorial, $inlinesourceparse, $class, $linenum, $filesourcepath) + .'
        '; + $this->template_options['desctranslate'] = $trans; + if (!isset($this->template_options['desctranslate'])) return $example; + if (!isset($this->template_options['desctranslate']['code'])) return $example; + $example = $this->template_options['desctranslate']['code'] . $example; + if (!isset($this->template_options['desctranslate']['/code'])) return $example; + return $example . $this->template_options['desctranslate']['/code']; + } + + /** + * @param string + */ + function TutorialExample($example) + { + $trans = $this->template_options['desctranslate']; + $this->template_options['desctranslate'] = array(); + $example = '
          ' . parent::TutorialExample($example) + .'
        '; + $this->template_options['desctranslate'] = $trans; + if (!isset($this->template_options['desctranslate'])) return $example; + if (!isset($this->template_options['desctranslate']['code'])) return $example; + $example = $this->template_options['desctranslate']['code'] . $example; + if (!isset($this->template_options['desctranslate']['/code'])) return $example; + return $example . $this->template_options['desctranslate']['/code']; + } + + /** + * Retrieve a Converter-specific anchor to a segment of a source code file + * parsed via a {@tutorial tags.filesource.pkg} tag. + * @param string full path to source file + * @param string name of anchor + * @param string link text, if this is a link + * @param boolean returns either a link or a destination based on this + * parameter + * @return string link to an anchor, or the anchor + */ + function getSourceAnchor($sourcefile,$anchor,$text = '',$link = false) + { + if ($link) + return $this->returnLink($this->getFileSourcePath('{$subdir}') . + PATH_DELIMITER . $this->getFileSourceName($sourcefile).'.html#a'.$anchor, $text); + else + return ''; + } + + function getCurrentPageLink() + { + return $this->curname . '.html'; + } + + function unmangle($sourcecode) + { + $sourcecode = str_replace(' ',' ',$sourcecode); + $sourcecode = str_replace('&','&',$sourcecode); + $sourcecode = str_replace('
        ',"
        ",$sourcecode); + $sourcecode = str_replace('','
        ',$sourcecode);
        +        $sourcecode = str_replace('','
        ',$sourcecode); + $sourcecode = str_replace('<','<',$sourcecode); + $sourcecode = str_replace('>','>',$sourcecode); + return $sourcecode; + } + + /** + * Uses htmlspecialchars() on the input + */ + function postProcess($text) + { + return htmlspecialchars($text); + } + + /** + * Use the template tutorial_toc.tpl to generate a table of contents for HTML + * @return string table of contents formatted for use in the current output format + * @param array format: array(array('tagname' => section, 'link' => returnsee link, 'id' => anchor name, 'title' => from title tag),...) + */ + function formatTutorialTOC($toc) + { + $template = &$this->newSmarty(); + $template->assign('toc',$toc); + return $template->fetch('tutorial_toc.tpl'); + } + + function &SmartyInit(&$templ) + { + $this->makeLeft(); + $templ->assign("ric",$this->ric_set); + $templ->assign("packageindex",$this->package_index); + $templ->assign('hastodos',count($this->todoList)); + $templ->assign('todolink','todolist.html'); + $templ->assign("subdir",''); + return $templ; + } + + /** + * Writes out the template file of {@link $class_data} and unsets the template to save memory + * @see registerCurrentClass() + * @see parent::endClass() + */ + function endClass() + { + $a = '../'; + if (!empty($this->subpackage)) $a .= '../'; + if ($this->juststarted) + { + $this->juststarted = false; + phpDocumentor_out("\n"); + flush(); + } + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->class_dir); + $this->class_data->assign("compiledclassindex",$this->getClassLeft()); + $this->class_data->assign("compiledfileindex",$this->getPageLeft()); + $this->class_data->assign("tutorials",$this->getTutorialList()); + $this->class_data->assign("contents",$this->getClassContents()); + $this->class_data->assign("packageindex",$this->package_index); + $this->class_data->assign("package",$this->package); + $this->class_data->assign("subdir",$a); + $this->class_data->register_outputfilter('HTMLSmarty_outputfilter'); + $this->writefile($this->class . '.html',$this->class_data->fetch('class.tpl')); + unset($this->class_data); + } + + function getTutorialList() + { + static $cache = false; + if ($cache) + { + if (isset($cache[$this->package])) return $cache[$this->package]; + } + $package = $this->package; + if (!isset($this->tutorials[$package])) return false; + foreach($this->tutorials[$package] as $subpackage => $blah) + { + $subpackages[] = $subpackage; + } + $tutes = array(); + foreach($subpackages as $subpackage) + { + if (isset($this->tutorial_tree) && is_array($this->tutorial_tree)) + foreach($this->tutorial_tree as $root => $tr) + { + if ($tr['tutorial']->package == $package && $tr['tutorial']->subpackage == $subpackage) + $tutes[$tr['tutorial']->tutorial_type][] = $this->getTutorialTree($tr['tutorial']); + } + } + $cache[$this->package] = $tutes; + return $tutes; + } + + function getTutorialTree($tutorial,$k = false) + { + $ret = ''; + if (is_object($tutorial)) $tree = parent::getTutorialTree($tutorial); else $tree = $tutorial; + if (!$tree) + { + $template = &$this->newSmarty(); + $template->assign('subtree',false); + $template->assign('name',str_replace('.','',$tutorial->name)); + $template->assign('parent',false); + $template->assign('haskids',false); + $template->assign('kids',''); + $link = new tutorialLink; + $t = $tutorial; + $link->addLink('',$t->path,$t->name,$t->package,$t->subpackage,$t->getTitle($this)); + $main = array('link' => $this->getId($link), 'title' => $link->title); + $template->assign('main',$main); + return $template->fetch('tutorial_tree.tpl'); + } + if (isset($tree['kids'])) + { + foreach($tree['kids'] as $subtree) + { + $ret .= $this->getTutorialTree($subtree, true); + } + } + $template = &$this->newSmarty(); + $template->assign('subtree',$k); + $template->assign('name',str_replace('.','',$tree['tutorial']->name)); + $template->assign('parent',($k ? str_replace('.','',$tree['tutorial']->parent->name) : false)); + $template->assign('haskids',strlen($ret)); + $template->assign('kids',$ret); + $link = new tutorialLink; + $t = $tree['tutorial']; + $link->addLink('',$t->path,$t->name,$t->package,$t->subpackage,$t->getTitle($this)); + $main = array('link' => $this->getId($link), 'title' => $link->title); + $template->assign('main',$main); + return $template->fetch('tutorial_tree.tpl'); + } + + function getClassLeft() + { + if ($this->_classleft_cache) + { + if (isset($this->_classleft_cache[$this->package][$this->subpackage])) return $this->_classleft_cache[$this->package][$this->subpackage]; + } + $arr = array(); + if (isset($this->left['#class'][$this->package])) + foreach($this->left['#class'][$this->package] as $subpackage => $pages) + { + $arr[$subpackage] = $pages; + } + $templ = &$this->newSmarty(); + $templ->assign('classleftindex',$arr); + $arr = $templ->fetch('classleft.tpl'); + $this->_classleft_cache[$this->package][$this->subpackage] = $arr; + return $arr; + } + + function getClassContents() + { + if ($this->_classcontents_cache) + { + if (isset($this->_classcontents_cache[$this->package][$this->subpackage][$this->class])) return $this->_classcontents_cache[$this->package][$this->subpackage][$this->class]; + } + $arr = array(); + foreach($this->class_contents[$this->package][$this->subpackage][$this->class] as $i => $link) + { + if (is_object($link)) + $arr[$link->type][] = $this->returnSee($link,$link->name); + } + $this->_classcontents_cache[$this->package][$this->subpackage][$this->class] = $arr; + return $arr; + } + + function getPageContents() + { + if (!isset($this->path)) $this->path = '#####'; + if ($this->_pagecontents_cache) + { + if (isset($this->_pagecontents_cache[$this->package][$this->subpackage][$this->path])) return $this->_pagecontents_cache[$this->package][$this->subpackage][$this->path]; + } + $arr = array(); + foreach($this->page_contents[$this->curpage->package][$this->curpage->subpackage] as $i => $link) + { + if (is_object($link)) + $arr[$link->type][$i] = $this->returnSee($link); + } + $this->_pagecontents_cache[$this->package][$this->subpackage][$this->path] = $arr; + return $arr; + } + + function getPageLeft() + { + if ($this->_pageleft_cache) + { + if (isset($this->_pageleft_cache[$this->package][$this->subpackage])) return $this->_pageleft_cache[$this->package][$this->subpackage]; + } + $arr = array(); + if (isset($this->left[$this->package])) + foreach($this->left[$this->package] as $subpackage => $pages) + { + $arr[$subpackage] = $pages; + } + $templ = &$this->newSmarty(); + $templ->assign('fileleftindex',$arr); + $arr = $templ->fetch('fileleft.tpl'); + $this->_pageleft_cache[$this->package][$this->subpackage] = $arr; + return $arr; + } + + /** + * Writes out the template file of {@link $page_data} and unsets the template to save memory + * @see registerCurrent() + * @see parent::endPage() + */ + function endPage() + { + $this->package = $this->curpage->package; + $this->subpackage = $this->curpage->subpackage; + $a = '../'; + if (!empty($this->subpackage)) $a .= '../'; + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->page_dir); + $this->page_data->assign("contents",$this->getPageContents()); + $this->page_data->assign("compiledfileindex",$this->getPageLeft()); + $this->page_data->assign("compiledclassindex",$this->getClassLeft()); + $this->page_data->assign("tutorials",$this->getTutorialList()); + $this->page_data->assign("packageindex",$this->package_index); + $this->page_data->assign("package",$this->package); + $this->page_data->assign("subdir",$a); + $this->page_data->register_outputfilter('HTMLSmarty_outputfilter'); + $this->writefile($this->page . '.html',$this->page_data->fetch('page.tpl')); + unset($this->page_data); + } + + /** + * @param string + * @param string + * @return string <a href="'.$link.'">'.$text.''.$text.''; + } + + function makeLeft() + { + if ($this->_done_package_index) return; + $this->_done_package_index = true; + if (!isset($this->package_index)) + foreach($this->all_packages as $key => $val) + { + if (isset($this->pkg_elements[$key])) + { + if (!isset($start)) $start = $key; + $this->package_index[] = array('link' => "li_$key.html", 'title' => $key); + } + } + foreach($this->page_elements as $package => $o1) + { + foreach($o1 as $subpackage => $links) + { + for($i=0;$ileft[$package][$subpackage][] = + array("link" => $this->getId($links[$i]), "title" => $links[$i]->name); + } + } + } + foreach($this->class_elements as $package => $o1) + { + foreach($o1 as $subpackage => $links) + { + for($i=0;$ileft['#class'][$package][$subpackage][] = + array("link" => $this->getId($links[$i]), "title" => $links[$i]->name); + } + } + } + } + + /** + * HTMLdefaultConverter chooses to format both package indexes and the complete index here + * + * This function formats output for the elementindex.html and pkgelementindex.html template files. It then + * writes them to the target directory + * @see generateElementIndex(), generatePkgElementIndex() + */ + function formatPkgIndex() + { + list($package_indexes,$packages,$mletters) = $this->generatePkgElementIndexes(); + for($i=0;$inewSmarty(); + $this->package = $package_indexes[$i]['package']; + $this->subpackage = ''; + $template->assign("compiledclassindex",$this->getClassLeft()); + $template->assign("compiledfileindex",$this->getPageLeft()); + $template->assign("tutorials",$this->getTutorialList()); + $template->assign("index",$package_indexes[$i]['pindex']); + $template->assign("package",$package_indexes[$i]['package']); + $template->assign("letters",$mletters[$package_indexes[$i]['package']]); + $template->assign("title","Package ".$package_indexes[$i]['package']." Element Index"); + $template->assign("date",date("r",time())); + $template->register_outputfilter('HTMLSmarty_outputfilter'); + $this->setTargetDir($this->base_dir); + $this->writefile('elementindex_'.$package_indexes[$i]['package'].'.html',$template->fetch('pkgelementindex.tpl')); + } + phpDocumentor_out("\n"); + flush(); + } + + /** + * HTMLdefaultConverter uses this function to format template index.html and packages.html + * + * This function generates the package list from {@link $all_packages}, eliminating any + * packages that don't have any entries in their package index (no files at all, due to @ignore + * or other factors). Then it uses the default package name as the first package index to display. + * It sets the right pane to be either a blank file with instructions on making package-level docs, + * or the package-level docs for the default package. + * @global string Used to set the starting package to display + */ + function formatIndex() + { + global $phpDocumentor_DefaultPackageName; + if (!isset($this->package_index)) + { + debug("\nERROR: Nothing parsed, check the command-line"); + die(); + } + list($elindex,$mletters) = $this->generateElementIndex(); + $template = &$this->newSmarty(); + $template->assign("index",$elindex); + $template->assign("letters",$mletters); + $template->assign("title","Element Index"); + $template->assign("date",date("r",time())); + phpDocumentor_out("\n"); + flush(); + $this->setTargetDir($this->base_dir); + $template->register_outputfilter('HTMLSmarty_outputfilter'); + $this->writefile('elementindex.html',$template->fetch('elementindex.tpl')); + usort($this->package_index,"HTMLSmarty_pindexcmp"); + $index = &$this->newSmarty(); + foreach($this->all_packages as $key => $val) + { + if (isset($this->pkg_elements[$key])) + { + if (!isset($start)) $start = $key; + if (!isset($this->package_pages[$key])) $this->writeNewPPage($key); + } + } + // Created index.html + $start = $phpDocumentor_DefaultPackageName; + if (!isset($this->pkg_elements[$key])) + { + // if there are no elements, use a random package as the default + $start = array_shift(array_keys($this->pkg_elements)); + } + $this->package = $start; + $this->subpackage = ''; + $index->assign("compiledclassindex",$this->getClassLeft()); + $index->assign("compiledfileindex",$this->getPageLeft()); + $index->assign('hastodos',count($this->todoList)); + $index->assign('todolink','todolist.html'); + $index->assign("tutorials",$this->getTutorialList()); + $index->assign("date",date("r",time())); + $index->assign("package",$this->package); + $index->assign("title",$this->title); + $index->assign("start","li_$start.html"); + if (isset($this->package_pages[$start])) + { + $index->assign("contents",$this->package_pages[$start]); + } + $index->register_outputfilter('HTMLSmarty_outputfilter'); + phpDocumentor_out("\n"); + flush(); + $this->setTargetDir($this->base_dir); + $this->writefile("index.html",$index->fetch('index.tpl')); + unset($index); + + } + + function writeNewPPage($key) + { + $template = &$this->newSmarty(); + $this->package = $key; + $this->subpackage = ''; + $template->assign("compiledclassindex",$this->getClassLeft()); + $template->assign("compiledfileindex",$this->getPageLeft()); + $template->assign("tutorials",$this->getTutorialList()); + $template->assign("date",date("r",time())); + $template->assign("title",$this->title); + $template->assign("package",$key); + $template->register_outputfilter('HTMLSmarty_outputfilter'); + phpDocumentor_out("\n"); + flush(); + $this->setTargetDir($this->base_dir); + $this->writefile("li_$key.html",$template->fetch('index.tpl')); + unset($template); + } + + /** + * Generate indexes for li_package.html and classtree output files + * + * This function generates the li_package.html files from the template file left.html. It does this by + * iterating through each of the $page_elements, $class_elements and $function_elements arrays to retrieve + * the pre-sorted {@link abstractLink} descendants needed for index generation. Conversion of these links to + * text is done by {@link returnSee()}. + * + * Then it uses {@link generateFormattedClassTrees()} to create class trees from the template file classtrees.html. Output + * filename is classtrees_packagename.html. This function also unsets {@link $elements} and {@link $pkg_elements} to free + * up the considerable memory these two class vars use + * @see $page_elements, $class_elements, $function_elements + */ + function formatLeftIndex() + { + phpDocumentor_out("\n"); + flush(); + $this->setTargetDir($this->base_dir); + if (!isset($this->left)) + { + debug("Nothing parsed, check the command-line"); + die(); + } + foreach($this->all_packages as $package => $rest) + { + if (!isset($this->pkg_elements[$package])) continue; + // Create class tree page + $template = &$this->newSmarty(); + $template->assign("compiledclassindex",$this->getClassLeft()); + $template->assign("compiledfileindex",$this->getPageLeft()); + $template->assign("classtrees",$this->generateFormattedClassTrees($package)); + $template->assign("package",$package); + $template->assign("date",date("r",time())); + $template->assign("title","Class Trees for Package $package"); + $template->register_outputfilter('HTMLSmarty_outputfilter'); + $this->writefile("classtrees_$package.html",$template->fetch('classtrees.tpl')); + phpDocumentor_out("\n"); + flush(); + } + $this->writeRIC(); + // free up considerable memory + unset($this->elements); + unset($this->pkg_elements); + } + + + /** + * This function takes an {@link abstractLink} descendant and returns an html link + * + * @param abstractLink a descendant of abstractlink should be passed, and never text + * @param string text to display in the link + * @param boolean this parameter is not used, and is deprecated + * @param boolean determines whether the returned text is enclosed in an <a> tag + */ + function returnSee(&$element, $eltext = false, $with_a = true) + { + if (!is_object($element) || !$element) return false; + if (!$with_a) return $this->getId($element, false); + if (!$eltext) + { + $eltext = ''; + switch($element->type) + { + case 'tutorial' : + $eltext = strip_tags($element->title); + break; + case 'method' : + case 'var' : + case 'const' : + $eltext .= $element->class.'::'; + case 'page' : + case 'define' : + case 'class' : + case 'function' : + case 'global' : + default : + $eltext .= $element->name; + if ($element->type == 'function' || $element->type == 'method') $eltext .= '()'; + break; + } + } + return ''.$eltext.''; + } + + function getId($element, $fullpath = true) + { + if (phpDocumentor_get_class($element) == 'parserdata') + { + $element = $this->addLink($element->parent); + $elp = $element->parent; + } elseif (is_a($element, 'parserbase')) + { + $elp = $element; + $element = $this->addLink($element); + } + $c = ''; + if (!empty($element->subpackage)) + { + $c = '/'.$element->subpackage; + } + $b = '{$subdir}'; + switch ($element->type) + { + case 'page' : + if ($fullpath) + return $b.$element->package.$c.'/'.$element->fileAlias.'.html'; + return 'top'; + break; + case 'define' : + case 'global' : + case 'function' : + if ($fullpath) + return $b.$element->package.$c.'/'.$element->fileAlias.'.html#'.$element->type.$element->name; + return $element->type.$element->name; + break; + case 'class' : + if ($fullpath) + return $b.$element->package.$c.'/'.$element->name.'.html'; + return 'top'; + break; + case 'method' : + case 'var' : + case 'const' : + if ($fullpath) + return $b.$element->package.$c.'/'.$element->class.'.html#'.$element->type.$element->name; + return $element->type.$element->name; + break; + case 'tutorial' : + $d = ''; + if ($element->section) + { + $d = '#'.$element->section; + } + return $b.$element->package.$c.'/tutorial_'.$element->name.'.html'.$d; + } + } + + /** + * Convert README/INSTALL/CHANGELOG file contents to output format + * @param README|INSTALL|CHANGELOG + * @param string contents of the file + */ + function Convert_RIC($name, $contents) + { + $this->ric_contents[$name] = $contents; + $this->ric_set[] = array('file' => 'ric_'.$name . '.html','name' => $name); + } + + function writeRIC() + { + if ($this->_ric_done) return; + $this->_ric_done = true; + foreach($this->ric_contents as $name => $contents) + { + $template = &$this->newSmarty(); + $template->assign('contents',$contents); + $template->assign('name',$name); + $template->assign('title',$name); + $this->setTargetDir($this->base_dir); + $this->writefile('ric_'.$name . '.html',$template->fetch('ric.tpl')); + } + } + + function ConvertTodoList() + { + $todolist = array(); + foreach($this->todoList as $package => $alltodos) + { + foreach($alltodos as $todos) + { + $converted = array(); + $converted['link'] = $this->returnSee($todos[0]); + if (!is_array($todos[1])) + { + $converted['todos'][] = $todos[1]->Convert($this); + } else + { + foreach($todos[1] as $todo) + { + $converted['todos'][] = $todo->Convert($this); + } + } + $todolist[$package][] = $converted; + } + } + $templ = &$this->newSmarty(); + $templ->assign('todos',$todolist); + $templ->register_outputfilter('HTMLSmarty_outputfilter'); + $this->setTargetDir($this->base_dir); + $this->writefile('todolist.html',$templ->fetch('todolist.tpl')); + } + + /** + * Create errors.html template file output + * + * This method takes all parsing errors and warnings and spits them out ordered by file and line number. + * @global ErrorTracker We'll be using it's output facility + */ + function ConvertErrorLog() + { + global $phpDocumentor_errors; + $allfiles = array(); + $files = array(); + $warnings = $phpDocumentor_errors->returnWarnings(); + $errors = $phpDocumentor_errors->returnErrors(); + $template = &$this->newSmarty(); + foreach($warnings as $warning) + { + $file = '##none'; + $linenum = 'Warning'; + if ($warning->file) + { + $file = $warning->file; + $allfiles[$file] = 1; + $linenum .= ' on line '.$warning->linenum; + } + $files[$file]['warnings'][] = array('name' => $linenum, 'listing' => $warning->data); + } + foreach($errors as $error) + { + $file = '##none'; + $linenum = 'Error'; + if ($error->file) + { + $file = $error->file; + $allfiles[$file] = 1; + $linenum .= ' on line '.$error->linenum; + } + $files[$file]['errors'][] = array('name' => $linenum, 'listing' => $error->data); + } + $i=1; + $af = array(); + foreach($allfiles as $file => $num) + { + $af[$i++] = $file; + } + $allfiles = $af; + usort($allfiles,'strnatcasecmp'); + $allfiles[0] = "Post-parsing"; + foreach($allfiles as $i => $a) + { + $allfiles[$i] = array('file' => $a); + } + $out = array(); + foreach($files as $file => $data) + { + if ($file == '##none') $file = 'Post-parsing'; + $out[$file] = $data; + } + $template->assign("files",$allfiles); + $template->assign("all",$out); + $template->assign("title","phpDocumentor Parser Errors and Warnings"); + $template->register_outputfilter('HTMLSmarty_outputfilter'); + $this->setTargetDir($this->base_dir); + $this->writefile("errors.html",$template->fetch('errors.tpl')); + unset($template); + phpDocumentor_out("\n\nTo view errors and warnings, look at ".$this->base_dir. PATH_DELIMITER . "errors.html\n"); + flush(); + } + + function getCData($value) + { + return '
        '.htmlentities($value).'
        '; + } + + function getTutorialId($package,$subpackage,$tutorial,$id) + { + return $id; + } + + /** + * Converts package page and sets its package as used in {@link $package_pages} + * @param parserPackagePage + */ + function convertPackagepage(&$element) + { + phpDocumentor_out("\n"); + flush(); + $template = &$this->newSmarty(); + $this->package = $element->package; + $this->subpackage = ''; + $template->assign("compiledclassindex",$this->getClassLeft()); + $template->assign("compiledfileindex",$this->getPageLeft()); + $template->assign("tutorials",$this->getTutorialList()); + $template->assign("date",date("r",time())); + $template->assign("title",$this->title); + $template->assign("package",$element->package); + $x = $element->Convert($this); + $x = substr($x,strpos($x,'assign("contents",trim(substr($x,strpos($x,'>') + 1))); + $this->package_pages[$element->package] = trim(substr($x,strpos($x,'>') + 1)); + $template->register_outputfilter('HTMLSmarty_outputfilter'); + phpDocumentor_out("\n"); + flush(); + $this->setTargetDir($this->base_dir); + $this->writefile("li_".$element->package.".html",$template->fetch('index.tpl')); + unset($template); + } + + /** + * @param parserTutorial + */ + function convertTutorial(&$element) + { + phpDocumentor_out("\n"); + flush(); + $template = &parent::convertTutorial($element); + $this->package = $element->package; + $this->subpackage = $element->subpackage; + $template->assign("compiledclassindex",$this->getClassLeft()); + $template->assign("compiledfileindex",$this->getPageLeft()); + $template->assign("tutorials",$this->getTutorialList()); + $template->assign("title",strip_tags($element->getTitle($this))); + $contents = $element->Convert($this); + if ($element->name == $this->package . '.pkg') + { + $this->package_pages[$element->package] = $contents; + } + $a = '../'; + if (!empty($element->subpackage)) $a .= $a; + $template->assign("subdir",$a); + $a = ''; + if ($element->subpackage) $a = PATH_DELIMITER . $element->subpackage; + $template->register_outputfilter('HTMLSmarty_outputfilter'); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $element->package . $a); + $this->writeFile('tutorial_'.$element->name.'.html',$template->fetch('tutorial.tpl')); + if ($element->name == $element->package . '.pkg') + { + phpDocumentor_out("\n"); + flush(); + // package-level docs + $this->setTargetDir($this->base_dir); + $template->assign("subdir",''); + $this->writeFile('li_'.$element->package.'.html',$template->fetch('tutorial.tpl')); + } + unset($template); + } + + /** + * Converts class for template output + * @see prepareDocBlock(), generateChildClassList(), generateFormattedClassTree(), getFormattedConflicts() + * @see getFormattedInheritedMethods(), getFormattedInheritedVars() + * @param parserClass + */ + function convertClass(&$element) + { + parent::convertClass($element); + $this->class_dir = $element->docblock->package; + if (!empty($element->docblock->subpackage)) $this->class_dir .= PATH_DELIMITER . $element->docblock->subpackage; + $a = '../classtrees_'; + if ($element->docblock->subpackage != '') $a = "../$a"; + + $this->class_data->assign('subdir',$a); + $this->class_data->assign("title","Docs For Class " . $element->getName()); + $this->class_data->assign("page",$element->getName() . '.html'); + } + + /** + * Converts class variables for template output + * @see prepareDocBlock(), getFormattedConflicts() + * @param parserDefine + */ + function convertVar(&$element) + { + parent::convertVar($element, array('var_dest' => $this->getId($element,false))); + } + + /** + * Converts class variables for template output + * @see prepareDocBlock(), getFormattedConflicts() + * @param parserDefine + */ + function convertConst(&$element) + { + parent::convertConst($element, array('const_dest' => $this->getId($element,false))); + } + + /** + * Converts class methods for template output + * @see prepareDocBlock(), getFormattedConflicts() + * @param parserDefine + */ + function convertMethod(&$element) + { + parent::convertMethod($element, array('method_dest' => $this->getId($element,false))); + } + + /** + * Converts function for template output + * @see prepareDocBlock(), parserFunction::getFunctionCall(), getFormattedConflicts() + * @param parserFunction + */ + function convertFunction(&$element) + { + $funcloc = $this->getId($this->addLink($element)); + parent::convertFunction($element,array('function_dest' => $this->getId($element,false))); + } + + /** + * Converts include elements for template output + * @see prepareDocBlock() + * @param parserInclude + */ + function convertInclude(&$element) + { + parent::convertInclude($element, array('include_file' => '_'.strtr($element->getValue(),array('"' => '', "'" => '','.' => '_')))); + } + + /** + * Converts defines for template output + * @see prepareDocBlock(), getFormattedConflicts() + * @param parserDefine + */ + function convertDefine(&$element) + { + parent::convertDefine($element, array('define_link' => $this->getId($element,false))); + } + + /** + * Converts global variables for template output + * @param parserGlobal + * @see prepareDocBlock(), getFormattedConflicts() + */ + function convertGlobal(&$element) + { + parent::convertGlobal($element, array('global_link' => $this->getId($element,false))); + } + + /** + * converts procedural pages for template output + * @see prepareDocBlock(), getClassesOnPage() + * @param parserData + */ + function convertPage(&$element) + { + parent::convertPage($element); + $this->juststarted = true; + $this->page_dir = $element->parent->package; + if (!empty($element->parent->subpackage)) $this->page_dir .= PATH_DELIMITER . $element->parent->subpackage; + // registering stuff on the template + $a = '../'; + if (!empty($element->docblock->subpackage)) $a = $a . $a; + $this->page_data->assign('subdir',$a); + $this->page_data->assign("page",$this->getPageName($element) . '.html'); + $this->page_data->assign("title","Docs for page ".$element->parent->getFile()); + } + + function getPageName(&$element) + { + if (phpDocumentor_get_class($element) == 'parserpage') return '_'.$element->getName(); + return '_'.$element->parent->getName(); + } + + /** + * returns an array containing the class inheritance tree from the root object to the class + * + * @param parserClass class variable + * @return array Format: array(root,child,child,child,...,$class) + * @uses parserClass::getParentClassTree() + */ + + function generateFormattedClassTree($class) + { + $tree = $class->getParentClassTree($this); + $out = ''; + if (count($tree) - 1) + { + $result = array($class->getName()); + $parent = $tree[$class->getName()]; + $distance[] = ''; + while ($parent) + { + $x = $parent; + if (is_object($parent)) + { + $subpackage = $parent->docblock->subpackage; + $package = $parent->docblock->package; + $x = $parent; + $x = $parent->getLink($this); + if (!$x) $x = $parent->getName(); + } + $result[] = + $x; + $distance[] = + "\n%s|\n" . + "%s--"; + if (is_object($parent)) + $parent = $tree[$parent->getName()]; + elseif (isset($tree[$parent])) + $parent = $tree[$parent]; + } + $nbsp = ' '; + for($i=count($result) - 1;$i>=0;$i--) + { + $my_nbsp = ''; + for($j=0;$jarray_reverse($result),'distance'=>array_reverse($distance)); + } else + { + return array('classes'=>$class->getName(),'distance'=>array('')); + } + } + + /** @access private */ + function sortVar($a, $b) + { + return strnatcasecmp($a->getName(),$b->getName()); + } + + /** @access private */ + function sortMethod($a, $b) + { + if ($a->isConstructor) return -1; + if ($b->isConstructor) return 1; + return strnatcasecmp($a->getName(),$b->getName()); + } + + /** + * returns a template-enabled array of class trees + * + * @param string $package package to generate a class tree for + * @see $roots, HTMLConverter::getRootTree() + */ + function generateFormattedClassTrees($package) + { + if (!isset($this->roots[$package])) return array(); + $roots = $trees = array(); + $roots = $this->roots[$package]; + for($i=0;$i $roots[$i],'class_tree' => "
          \n".$this->getRootTree($this->getSortedClassTreeFromClass($roots[$i],$package,''),$package)."
        \n"); + } + return $trees; + } + + /** + * return formatted class tree for the Class Trees page + * + * @param array $tree output from {@link getSortedClassTreeFromClass()} + * @see Classes::$definitechild, generateFormattedClassTrees() + * @return string + */ + function getRootTree($tree,$package) + { + if (!$tree) return ''; + $my_tree = ''; + $cur = '#root'; + $lastcur = array(false); + $kids = array(); + $dopar = false; + if ($tree[$cur]['parent']) + { + $dopar = true; + if (!is_object($tree[$cur]['parent'])) + { +// debug("parent ".$tree[$cur]['parent']." not found"); + $my_tree .= '
      • ' . $tree[$cur]['parent'] .'
          '; + } + else + { +// debug("parent ".$this->returnSee($tree[$cur]['parent'])." in other package"); + $my_tree .= '
        • ' . $this->returnSee($tree[$cur]['parent']); + if ($tree[$cur]['parent']->package != $package) $my_tree .= ' (Different package)
            '; + } + } + do + { +// fancy_debug($cur,$lastcur,$kids); + if (count($tree[$cur]['children'])) + { +// debug("$cur has children"); + if (!isset($kids[$cur])) + { +// debug("set $cur kids"); + $kids[$cur] = 1; + $my_tree .= '
          • '.$this->returnSee($tree[$cur]['link']); + $my_tree .= '
              '."\n"; + } + array_push($lastcur,$cur); + list(,$cur) = each($tree[$cur]['children']); +// var_dump('listed',$cur); + if ($cur) + { + $cur = $cur['package'] . '#' . $cur['class']; +// debug("set cur to child $cur"); +// $my_tree .= '
            • '.$this->returnSee($tree[$cur]['link']); + continue; + } else + { +// debug("end of children for $cur"); + $cur = array_pop($lastcur); + $cur = array_pop($lastcur); + $my_tree .= '
          • '."\n"; + if ($dopar && ($cur == '#root' || !$cur)) $my_tree .= '
        • '; + } + } else + { +// debug("$cur has no children"); + $my_tree .= '
        • '.$this->returnSee($tree[$cur]['link'])."
        • "; + if ($dopar && $cur == '#root') $my_tree .= '
      • '; + $cur = array_pop($lastcur); + } + } while ($cur); + return $my_tree; + } + /** + * Generate indexing information for given element + * + * @param parserElement descendant of parserElement + * @see generateElementIndex() + * @return array + */ + function getIndexInformation($elt) + { + $Result['type'] = $elt->type; + $Result['file_name'] = $elt->file; + $Result['path'] = $elt->getPath(); + + if (isset($elt->docblock)) + { + $Result['description'] = $elt->docblock->getSDesc($this); + + if ($elt->docblock->hasaccess) + $Result['access'] = $elt->docblock->tags['access'][0]->value; + else + $Result['access'] = 'public'; + + $Result['abstract'] = isset ($elt->docblock->tags['abstract'][0]); + } + else + $Result['description'] = ''; + + $aa = $Result['description']; + if (!empty($aa)) $aa = "
            $aa"; + + switch($elt->type) + { + case 'class': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Class'; + $Result['link'] = $this->getClassLink($elt->getName(), + $elt->docblock->package, + $elt->getPath(), + $elt->getName()); + $Result['listing'] = 'in file '.$elt->file.', class '.$Result['link']."$aa"; + break; + case 'define': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Constant'; + $Result['link'] = $this->getDefineLink($elt->getName(), + $elt->docblock->package, + $elt->getPath(), + $elt->getName()); + $Result['listing'] = 'in file '.$elt->file.', constant '.$Result['link']."$aa"; + break; + case 'global': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Global'; + $Result['link'] = $this->getGlobalLink($elt->getName(), + $elt->docblock->package, + $elt->getPath(), + $elt->getName()); + $Result['listing'] = 'in file '.$elt->file.', global variable '.$Result['link']."$aa"; + break; + case 'function': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Function'; + $Result['link'] = $this->getFunctionLink($elt->getName(), + $elt->docblock->package, + $elt->getPath(), + $elt->getName().'()'); + $Result['listing'] = 'in file '.$elt->file.', function '.$Result['link']."$aa"; + break; + case 'method': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Method'; + $Result['link'] = $this->getMethodLink($elt->getName(), + $elt->class, + $elt->docblock->package, + $elt->getPath(), + $elt->class.'::'.$elt->getName().'()' + ); + if ($elt->isConstructor) $Result['constructor'] = 1; + $Result['listing'] = 'in file '.$elt->file.', method '.$Result['link']."$aa"; + break; + case 'var': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Variable'; + $Result['link'] = $this->getVarLink($elt->getName(), + $elt->class, + $elt->docblock->package, + $elt->getPath(), + $elt->class.'::'.$elt->getName()); + $Result['listing'] = 'in file '.$elt->file.', variable '.$Result['link']."$aa"; + break; + case 'const': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Variable'; + $Result['link'] = $this->getConstLink($elt->getName(), + $elt->class, + $elt->docblock->package, + $elt->getPath(), + $elt->class.'::'.$elt->getName()); + $Result['listing'] = 'in file '.$elt->file.', class constant '.$Result['link']."$aa"; + break; + case 'page': + $Result['name'] = $elt->getFile(); + $Result['title'] = 'Page'; + $Result['link'] = $this->getPageLink($elt->getFile(), + $elt->package, + $elt->getPath(), + $elt->getFile()); + $Result['listing'] = 'procedural page '.$Result['link']; + break; + case 'include': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Include'; + $Result['link'] = $elt->getValue(); + $Result['listing'] = 'include '.$Result['name']; + break; + } + + return $Result; + } + /** + * Generate alphabetical index of all elements + * + * @see $elements, walk() + */ + function generateElementIndex() + { + $elementindex = array(); + $letters = array(); + $used = array(); + foreach($this->elements as $letter => $nutoh) + { + foreach($this->elements[$letter] as $i => $yuh) + { + if ($this->elements[$letter][$i]->type != 'include') + { + if (!isset($used[$letter])) + { + $letters[]['letter'] = $letter; + $elindex['letter'] = $letter; + $used[$letter] = 1; + } + + $elindex['index'][] = $this->getIndexInformation($this->elements[$letter][$i]); + } + } + if (isset($elindex['index'])) + { + $elementindex[] = $elindex; + } else + { + unset($letters[count($letters) - 1]); + } + $elindex = array(); + } + return array($elementindex,$letters); + } + + function copyMediaRecursively($media,$targetdir,$subdir = '') + { + if (!is_array($media)) { + return; + } + foreach($media as $dir => $files) + { + if ($dir === '/') + { + $this->copyMediaRecursively($files,$targetdir); + } else + { + if (!is_numeric($dir)) + { + // create the subdir + phpDocumentor_out("creating $targetdir/$dir\n"); + Converter::setTargetDir($targetdir . PATH_DELIMITER . $dir); + if (!empty($subdir)) $subdir .= PATH_DELIMITER; + $this->copyMediaRecursively($files,"$targetdir/$dir",$subdir . $dir); + } else + { + // copy the file + phpDocumentor_out("copying $targetdir/".$files['file']."\n"); + $this->copyFile($files['file'],$subdir); + } + } + } + } + + /** + * calls the converter setTargetDir, and then copies any template images and the stylesheet if they haven't been copied + * @see Converter::setTargetDir() + */ + function setTargetDir($dir) + { + Converter::setTargetDir($dir); + if ($this->_wrote_tdir) return; + $this->_wrote_tdir = true; + $template_images = array(); + $stylesheets = array(); + $tdir = $dir; + $dir = $this->templateDir; + $this->templateDir = $this->templateDir.'templates/'; + $info = new Io; + $this->copyMediaRecursively($info->getDirTree($this->templateDir.'media',$this->templateDir),$tdir); + } + + /** + * Generate alphabetical index of all elements by package and subpackage + * + * @param string $package name of a package + * @see $pkg_elements, walk(), generatePkgElementIndexes() + */ + function generatePkgElementIndex($package) + { + $elementindex = array(); + $letters = array(); + $letterind = array(); + $used = array(); + $subp = ''; + foreach($this->pkg_elements[$package] as $subpackage => $els) + { + if (empty($els)) continue; + if (!empty($subpackage)) $subp = " (subpackage: $subpackage)"; else $subp = ''; + foreach($els as $letter => $yuh) + { + foreach($els[$letter] as $i => $yuh) + { + if ($els[$letter][$i]->type != 'include') + { + if (!isset($used[$letter])) + { + $letters[]['letter'] = $letter; + $letterind[$letter] = count($letters) - 1; + $used[$letter] = 1; + } + $elindex[$letter]['letter'] = $letter; + + $elindex[$letter]['index'][] = $this->getIndexInformation($els[$letter][$i]); + } + } + } + } + ksort($elindex); + usort($letters,'HTMLSmarty_lettersort'); + if (isset($elindex)) + { + while(list($letter,$tempel) = each($elindex)) + { + if (!isset($tempel)) + { + unset($letters[$letterind[$tempel['letter']]]); + } else + $elementindex[] = $tempel; + } + } else $letters = array(); + return array($elementindex,$letters); + } + + /** + * + * @see generatePkgElementIndex() + */ + function generatePkgElementIndexes() + { + $packages = array(); + $package_names = array(); + $pkg = array(); + $letters = array(); + foreach($this->pkg_elements as $package => $trash) + { + $pkgs['package'] = $package; + $pkg['package'] = $package; + list($pkg['pindex'],$letters[$package]) = $this->generatePkgElementIndex($package); + if (count($pkg['pindex'])) + { + $packages[] = $pkg; + $package_names[] = $pkgs; + } + unset($pkgs); + unset($pkg); + } + foreach($packages as $i => $package) + { + $pnames = array(); + for($j=0;$jreturnSee($a, $text, $with_a); + } + + /** + * @param string name of function + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the function's documentation + * @see parent::getFunctionLink() + */ + function getFunctionLink($expr,$package, $file = false,$text = false) + { + $a = Converter::getFunctionLink($expr,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of define + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the define's documentation + * @see parent::getDefineLink() + */ + function getDefineLink($expr,$package, $file = false,$text = false) + { + $a = Converter::getDefineLink($expr,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of global variable + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the global variable's documentation + * @see parent::getGlobalLink() + */ + function getGlobalLink($expr,$package, $file = false,$text = false) + { + $a = Converter::getGlobalLink($expr,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of procedural page + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the procedural page's documentation + * @see parent::getPageLink() + */ + function getPageLink($expr,$package, $path = false,$text = false) + { + $a = Converter::getPageLink($expr,$package,$path); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of method + * @param string class containing method + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the method's documentation + * @see parent::getMethodLink() + */ + function getMethodLink($expr,$class,$package, $file = false,$text = false) + { + $a = Converter::getMethodLink($expr,$class,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of var + * @param string class containing var + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the var's documentation + * @see parent::getVarLink() + */ + function getVarLink($expr,$class,$package, $file = false,$text = false) + { + $a = Converter::getVarLink($expr,$class,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of class constant + * @param string class containing class constant + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the var's documentation + * @see parent::getVarLink() + */ + function getConstLink($expr,$class,$package, $file = false,$text = false) + { + $a = Converter::getConstLink($expr,$class,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * does a nat case sort on the specified second level value of the array + * + * @param mixed $a + * @param mixed $b + * @return int + */ + function rcNatCmp ($a, $b) + { + $aa = strtoupper($a[$this->rcnatcmpkey]); + $bb = strtoupper($b[$this->rcnatcmpkey]); + + return strnatcasecmp($aa, $bb); + } + + /** + * does a nat case sort on the specified second level value of the array. + * this one puts constructors first + * + * @param mixed $a + * @param mixed $b + * @return int + */ + function rcNatCmp1 ($a, $b) + { + $aa = strtoupper($a[$this->rcnatcmpkey]); + $bb = strtoupper($b[$this->rcnatcmpkey]); + + if (strpos($aa,'CONSTRUCTOR') === 0) + { + return -1; + } + if (strpos($bb,'CONSTRUCTOR') === 0) + { + return 1; + } + if (strpos($aa,strtoupper($this->class)) === 0) + { + return -1; + } + if (strpos($bb,strtoupper($this->class)) === 0) + { + return -1; + } + return strnatcasecmp($aa, $bb); + } + + /** + * This function is not used by HTMLdefaultConverter, but is required by Converter + */ + function Output() + { + } +} + +/** + * @access private + * @global string name of the package to set as the first package + */ +function HTMLSmarty_pindexcmp($a, $b) +{ + global $phpDocumentor_DefaultPackageName; + if ($a['title'] == $phpDocumentor_DefaultPackageName) return -1; + if ($b['title'] == $phpDocumentor_DefaultPackageName) return 1; + return strnatcasecmp($a['title'],$b['title']); +} + +/** @access private */ +function HTMLSmarty_lettersort($a, $b) +{ + return strnatcasecmp($a['letter'],$b['letter']); +} + +/** @access private */ +function HTMLSmarty_outputfilter($src, &$smarty) +{ + return str_replace('{$subdir}',$smarty->_tpl_vars['subdir'],$src); +} +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/options.ini b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/options.ini new file mode 100644 index 00000000..4566db60 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/options.ini @@ -0,0 +1,577 @@ +preservedocbooktags = false + +;; used to highlight the {@source} inline tag, @filesource tag, and @example tag +[highlightSourceTokens] +;; format: +;; T_CONSTANTNAME = open +;; /T_CONSTANTNAME = close + +T_INCLUDE = +/T_INCLUDE = +T_INCLUDE_ONCE = +/T_INCLUDE_ONCE = +T_REQUIRE_ONCE = +/T_REQUIRE_ONCE = +T_REQUIRE_ONCE = +/T_REQUIRE_ONCE = + +T_CONSTANT_ENCAPSED_STRING = +/T_CONSTANT_ENCAPSED_STRING = +T_STRING_VARNAME = +/T_STRING_VARNAME = + +T_STRING = +/T_STRING = + +T_DNUMBER = +/T_DNUMBER = +T_LNUMBER = +/T_LNUMBER = + +T_VARIABLE = +/T_VARIABLE = + +T_COMMENT = +/T_COMMENT = +T_ML_COMMENT = +/T_ML_COMMENT = + +T_OBJECT_OPERATOR = +/T_OBJECT_OPERATOR = + +T_ABSTRACT = +/T_ABSTRACT = +T_CLONE = +/T_CLONE = +T_HALT_COMPILER = +/T_HALT_COMPILER = +T_ARRAY = +/T_ARRAY = +T_AS = +/T_AS = +T_BREAK = +/T_BREAK = +T_CLASS = +/T_CLASS = +T_CASE = +/T_CASE = +T_CONST = +/T_CONST = +T_CONTINUE = +/T_CONTINUE = +T_DECLARE = +/T_DECLARE = +T_DEFAULT = +/T_DEFAULT = +T_ELSE = +/T_ELSE = +T_ELSEIF = +/T_ELSEIF = +T_EMPTY = +/T_EMPTY = +T_ENDDECLARE = +/T_ENDDECLARE = +T_ENDFOR = +/T_ENDFOR = +T_ENDSWITCH = +/T_ENDSWITCH = +T_ENDFOREACH = +/T_ENDFOREACH = +T_ENDIF = +/T_ENDIF = +T_ENDWHILE = +/T_ENDWHILE = +T_EXIT = +/T_EXIT = +T_EXTENDS = +/T_EXTENDS = +T_FINAL = +/T_FINAL = +T_FOR = +/T_FOR = +T_FOREACH = +/T_FOREACH = +T_FUNCTION = +/T_FUNCTION = +T_GLOBAL = +/T_GLOBAL = +T_IF = +/T_IF = +T_IMPLEMENTS = +/T_IMPLEMENTS = +T_INTERFACE = +/T_INTERFACE = +T_LOGICAL_AND = +/T_LOGICAL_AND = +T_LOGICAL_OR = +/T_LOGICAL_OR = +T_LOGICAL_XOR = +/T_LOGICAL_XOR = +T_NEW = +/T_NEW = +T_PRIVATE = +/T_PRIVATE = +T_PROTECTED = +/T_PROTECTED = +T_PUBLIC = +/T_PUBLIC = +T_RETURN = +/T_RETURN = +T_STATIC = +/T_STATIC = +T_SWITCH = +/T_SWITCH = +T_VAR = +/T_VAR = +T_WHILE = +/T_WHILE = + +T_DOUBLE_COLON = +/T_DOUBLE_COLON = + +T_OPEN_TAG = +/T_OPEN_TAG = +T_OPEN_TAG_WITH_ECHO = +/T_OPEN_TAG_WITH_ECHO = +T_CLOSE_TAG = +/T_CLOSE_TAG = + + +[highlightSource] +;; this is for highlighting things that aren't tokens like "&" +;; format: +;; word = open +;; /word = close +@ = +/@ = +& = +/& = +[ = +/[ = +] = +/] = +! = +/! = +";" = +/; = +( = +/( = +) = +/) = +, = +/, = +{ = +/{ = +} = +/} = +""" = +/" = + +[highlightDocBlockSourceTokens] +;; this is for docblock tokens, using by phpDocumentor_HighlightParser +;; tagphptype is for "string" in @param string description, for example +docblock = +/docblock = +tagphptype = +/tagphptype = +tagvarname = +/tagvarname = +coretag = +/coretag = +tag = +/tag = +inlinetag = +/inlinetag = +internal = +/internal = +closetemplate = +/closetemplate = +docblocktemplate = +/docblocktemplate = + +[highlightTutorialSourceTokens] +;; this is for XML DocBook-based tutorials, highlighted by phpDocumentor_TutorialHighlightParser +;; +opentag = +/opentag = +;; +closetag = +/closetag = +;; +attribute = +/attribute = +;; +attributevalue = +/attributevalue = +;; &entity; +entity = +/entity = +;; +comment = +/comment = +;; {@inline tag} +itag = +/itag = + +;; used for translation of html in DocBlocks +[desctranslate] +ul =
          +/ul =
        +ol =
          +/ol =
        +li =
      • +/li =
      • +code =
        +/code = 
        +var = +/var = +samp = +/samp = +kbd = +/kbd = +pre =
        +/pre = 
        +p =

        +/p =

        +b = +/b = +i = +/i = +br =
        + +[ppage] +;; this is the DocBook package page translation section. All DocBook tags +;; that have a corresponding html tag must be listed here. Entities should +;; also be listed here +;; +;; examples: +;; 1) +;; tagname = newtagname +;; +;; This is the simplest case, where all attributes will be added into the +;; starting tag and the ending tag will be html/xml style +;; becomes and +;; becomes +;; +;; +;; 2) +;; tagname = newtagname +;; tagname->attr = newattrname +;; +;; in this case, everything will be like the first case, except tags like: +;; will become +;; +;; +;; 3) +;; tagname = newtagname +;; tagname->attr = newattrname +;; tagname->attr+value = newvalue +;; +;; in this case, the value is also translated to another. This can be useful +;; for instances such as focus="middle" changing to align="center" or something +;; of that nature. +;; will become +;; +;; +;; 4) +;; tagname = newtagname +;; tagname->attr1 = newattrname +;; tagname->attr2 = newattrname +;; tagname->attr1+value|attr2+value = newvalue +;; +;; in this case, two attributes combine to make one new attribute, and the combined +;; value is translated into a new value +;; will become +;; +;; +;; 5) +;; tagname = newtagname +;; tagname!attr = dummy +;; +;; here, the attribute will be ignored. dummy is not used and may be any value +;; will become +;; +;; +;; 6) +;; tagname = newtagname +;; tagname! = dummy +;; +;; here, all attributes will be ignored. dummy is not used and may be any value +;; will become +;; +;; +;; 7) +;; tagname = newtagname +;; tagname/ = 1 +;; +;; here, the tag will be translated as a single tag with no closing tag, and all +;; attributes +;; {text text} will become +;; +;; +;; 8) +;; tagname = +;; /tagname = closetagtext +;; +;; in this case, the text will be inserted exactly as entered for +;; and closetagtext for +;; will become +;; closetagtext +;; +;; 9) +;; $attr$my_attribute = newattrname +;; +;; tagname = newtagname +;; +;; in this case, all occurences of my_attribute in any tag will be changed to +;; newattrname. This is useful for changing things like role="php" to +;; class="php," for example. Note that the text "$attr$" MUST be on the line +;; start for phpDocumentor to recognize it. +;; +;; 10) +;; &entity; = translation text +;; " = " +;; " = """ +;; < = < +;; +;; Use this to control translation of entities to their appropriate values + +  =   +" = " +” = ” +“ = “ +& = & +< = < +> = > +© = © + +$attr$role = class + +abbrev = abbr + +blockquote = blockquote + +arg = span +arg->choice = class + +author = +/author = +author! = 0 + +authorblurb =
        +/authorblurb =
        + +authorgroup =

        Authors

        +/authorgroup =
        +authorgroup! = 0 + +caution = +/caution = +caution! = 0 + +cmdsynopsis =
        +/cmdsynopsis =
        + +command = +/command = + +copyright =
        +/copyright =
        + +emphasis = strong + +example =
        +/example = 
        +example! = 0 + +function = +/function = () + +formalpara = p + +graphic = img +graphic->fileref = src +graphic/ = + +important = strong + +informalequation = blockquote + +informalexample = div + +inlineequation = em + +itemizedlist = ul + +listitem = li + +literal = code + +literallayout = span + +option = " " +/option = + +orderedlist = ol + +para = p + +programlisting =
        +/programlisting = 
        +programlisting! = 0 + +refentry = div + +refnamediv =
        +/refnamediv =
        +refnamediv! = 0 + +refname =

        +/refname =

        + +refpurpose =

        +/refpurpose =

        + +refsynopsisdiv =
        +/refsynopsisdiv =
        +refsynopsisdiv! = 0 + +refsect1 = span + +refsect2 = +/refsect2 =
        + +refsect3 = +/refsect3 =
        + +releaseinfo =
        ( +/releaseinfo = )
        + +simpara = +/simpara =
        +simpara! = 0 + +subscript = sub + +superscript = super + +table = table + +table->colsep = rules +table->rowsep = rules +table->colsep+1|rowsep+1 = all +table->colsep+1|rowsep+0 = cols +table->colsep+0|rowsep+1 = rows + +table->frame = frame +table->frame+all = border +table->frame+none = void +table->frame+sides = vsides +table->frame+top = above +table->frame+topbot = hsides + +thead = thead + +tfoot = tfoot + +tbody = tbody + +colspec = col + +tgroup = colgroup +tgroup/ = 1 +tgroup->cols = span + +row = tr + +entry = td +entry->morerows = colspan +entry->morerows+1 = 2 +entry->morerows+2 = 3 +entry->morerows+3 = 4 +entry->morerows+4 = 5 +entry->morerows+5 = 6 +entry->morerows+6 = 7 +entry->morerows+7 = 8 +entry->morerows+8 = 9 +entry->morerows+9 = 10 +entry->morerows+10 = 11 +;; add more if you need more colspans + +warning = +/warning = +warning! = 0 + +;; now begins the attributes that should be tags in cdata +[$attr$id] +open = a +;close = /a +cdata! = true +quotevalues = true +separator = "=" +;separateall = true +$id = name + +;; now begins the sections that deal with +[refsynopsisdiv_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <h1 class="title"> +close = </h1> + +[refsect1_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <h2 class="title"> +close = </h2> + +[refsect2_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <h3 class="title"> +close = </h3> + +[refsect3_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <h4 class="title"> +close = </h4> + +[para_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <div class="title"> +close = </div> + +[formalpara_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <div class="title"> +close = </div> + +[example_title] +;tag_attr = true +;attr_name = title +;cdata_start = true +cdata_end = true +open = </td></tr><tr><td><strong> +close = </strong> + +[table_title] +;tag_attr = true +;attr_name = true +cdata_start = true +open = <caption> +close = </caption> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/__tags.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/__tags.tpl new file mode 100644 index 00000000..221830c4 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/__tags.tpl @@ -0,0 +1,13 @@ +<div class="tag-list"> + {section name=tag loop=$tags} + {if $tags[tag].keyword != "abstract" && + $tags[tag].keyword != "access" && + $tags[tag].keyword != "static" && + $tags[tag].keyword != "version" + } + + <strong>{$tags[tag].keyword|capitalize}:</strong> + {$tags[tag].data}<br /> + {/if} + {/section} +</div> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_class_declaration.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_class_declaration.tpl new file mode 100644 index 00000000..d7fe2f82 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_class_declaration.tpl @@ -0,0 +1,38 @@ +<hr size="1" noshade="noshade"/> +<div class="class-declaration"> + {if count($tags) > 0} + {section name=tag loop=$tags} + {if $tags[tag].keyword == "abstract"} + abstract + {/if} + {/section} + {/if} + + {if $is_interface} + interface + {else} + class + {/if} + + <strong>{$class_name}</strong> + + {if count($class_tree) > 1} + {section name=tree loop=$class_tree.classes} + {if $smarty.section.tree.last} + extends {$class_tree.classes[$smarty.section.tree.index_prev]} + {/if} + {/section} + {/if} + + {if $implements} + <br/> + implements + {foreach item="interface" from=$implements} + {if !$smarty.foreach.interface.first} + , {$interface} + {else} + {$interface} + {/if} + {/foreach} + {/if} +</div> \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_class_description.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_class_description.tpl new file mode 100644 index 00000000..12025c1c --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_class_description.tpl @@ -0,0 +1,7 @@ +<div class="class-description"> + <p>{$sdesc}</p> + + {if $desc != ""}{$desc}{/if} +</div> + +{include file="_tags.tpl" tags=$tags} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_class_list.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_class_list.tpl new file mode 100644 index 00000000..d6a1d398 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_class_list.tpl @@ -0,0 +1 @@ +{eval var=$compiledclassindex} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_constant_details.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_constant_details.tpl new file mode 100644 index 00000000..bca71e17 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_constant_details.tpl @@ -0,0 +1,33 @@ +{if $consts} + <hr size="1" noshade="noshade"/> + <a name="constant-details"></a> + <table class="constant-details" cellspacing="1"> + <tr> + <th>Constant Details</th> + </tr> + {section name=const loop=$consts} + <tr> + <td> + <a name="{$consts[const].const_dest}"></a> + + <h3>{$consts[const].const_name}</h3> + + <p>{$consts[const].sdesc}</p> + + {if $consts[const].desc} + {$consts[const].desc} + {/if} + + <div class="tag-list"> + <h4 class="tag">Type:</h4> + <div class="tag-data">{include file="_get_constant_type.tpl" const=$consts[const].const_value}</div> + <h4 class="tag">Value:</h4> + <div class="tag-data">{$consts[const].const_value}</div> + </div> + {include file="_tags.tpl" tags=$consts[const].tags} + <p/> + </td> + </tr> + {/section} + </table> +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_constant_summary.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_constant_summary.tpl new file mode 100644 index 00000000..8049c4b0 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_constant_summary.tpl @@ -0,0 +1,22 @@ +{if $consts || $iconsts} + <hr size="1" noshade="noshade"/> + <a name="constant-summary"></a> + <table class="constant-summary" cellspacing="1"> + <tr> + <th colspan="3">Constant Summary</th> + </tr> + {section name=const loop=$consts} + <tr> + <td class="type" nowrap="nowrap">{strip}{include file="_get_constant_type.tpl" const=$consts[const].const_value}{/strip}</td> + <td class="name"><a href="{$consts[const].id}">{$consts[const].const_name}</a></td> + <td class="description" width="100%"> + {$consts[const].sdesc} + + {if $consts[const].desc} + {$consts[const].desc} + {/if} + </td> + </tr> + {/section} + </table> +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_constructor_details.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_constructor_details.tpl new file mode 100644 index 00000000..ec4fd0a2 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_constructor_details.tpl @@ -0,0 +1,55 @@ +{if $methods} + {section name=method loop=$methods} + {if $methods[method].function_name == "__construct"} + <hr size="1" noshade="noshade"/> + <a name="sec-method"></a> + <table class="method-details" cellspacing="1"> + <tr> + <th colspan="3">Constructor Details</th> + </tr> + <tr> + <td class="method-data"> + <a name="{$methods[method].method_dest}"></a> + + <h2>{$methods[method].function_name}</h2> + + <table class="method-detail" cellspacing="0"> + <tr> + <td nowrap="nowrap">{strip} + {if $methods[method].access == "protected"} + protected  + {/if} + + {if $methods[method].access == "public"} + public  + {/if} + + {if $methods[method].abstract == "1"} + abstract  + {/if} + + {if $methods[method].static == "1"} + static  + {/if} + + <strong>{$methods[method].function_name}</strong> + {/strip}</td> + <td nowrap="nowrap">{strip} + {$methods[method].ifunction_call.params} + {/strip}</td> + </tr> + </table> + + <p>{$methods[method].sdesc}</p> + + {if $methods[method].desc} + {$methods[method].desc} + {/if} + + {include file="_tags.tpl" tags=$methods[method].tags} + </td> + </tr> + </table> + {/if} + {/section} +{/if} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_constructor_summary.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_constructor_summary.tpl new file mode 100644 index 00000000..8819f63e --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_constructor_summary.tpl @@ -0,0 +1,25 @@ +{if $methods} + {section name=method loop=$methods} + {if $methods[method].function_name == "__construct"} + <hr size="1" noshade="noshade"/> + <a name="constructor-summary"></a> + <table class="method-summary" cellspacing="1"> + <tr> + <th colspan="2">Constructor Summary</th> + </tr> + <tr> + <td class="type" nowrap="nowrap" width="1%">{$methods[method].access}</td> + <td> + <div class="declaration"> + <a href="{$methods[method].id}">{$methods[method].function_name}</a> + {$methods[method].ifunction_call.params} + </div> + <div class="description"> + {$methods[method].sdesc} + </div> + </td> + </tr> + </table> + {/if} + {/section} +{/if} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_destructor_details.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_destructor_details.tpl new file mode 100644 index 00000000..3cb5534a --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_destructor_details.tpl @@ -0,0 +1,55 @@ +{if $methods} + {section name=method loop=$methods} + {if $methods[method].function_name == "__destruct"} + <hr size="1" noshade="noshade"/> + <a name="sec-method"></a> + <table class="method-details" cellspacing="1"> + <tr> + <th colspan="3">Destructor Details</th> + </tr> + <tr> + <td class="method-data"> + <a name="{$methods[method].method_dest}"></a> + + <h2>{$methods[method].function_name}</h2> + + <table class="method-detail" cellspacing="0"> + <tr> + <td nowrap="nowrap">{strip} + {if $methods[method].access == "protected"} + protected  + {/if} + + {if $methods[method].access == "public"} + public  + {/if} + + {if $methods[method].abstract == "1"} + abstract  + {/if} + + {if $methods[method].static == "1"} + static  + {/if} + + <strong>{$methods[method].function_name}</strong> + {/strip}</td> + <td nowrap="nowrap">{strip} + {build_argument_list args=$methods[method].ifunction_call.params style="vertical"} + {/strip}</td> + </tr> + </table> + + <p>{$methods[method].sdesc}</p> + + {if $methods[method].desc} + {$methods[method].desc} + {/if} + + {include file="_tags.tpl" tags=$methods[method].tags} + </td> + </tr> + </table> + {/if} + {/section} +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_destructor_summary.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_destructor_summary.tpl new file mode 100644 index 00000000..53e8f1d2 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_destructor_summary.tpl @@ -0,0 +1,27 @@ +{if $methods} + {section name=method loop=$methods} + {if $methods[method].function_name == "__destruct"} + <hr size="1" noshade="noshade"/> + <a name="desructor-summary"></a> + <table class="method-summary" cellspacing="1"> + <tr> + <th colspan="2">Destructor Summary</th> + </tr> + <tr> + <td class="type" nowrap="nowrap" width="1%">{strip} + {$methods[method].access} + {/strip}</td> + <td> + <div class="declaration">{strip} + <a href="{$methods[method].id}">{$methods[method].function_name}</a> + {$methods[method].ifunction_call.params} + {/strip}</div> + <div class="description"> + {$methods[method].sdesc} + </div> + </td> + </tr> + </table> + {/if} + {/section} +{/if} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_footer.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_footer.tpl new file mode 100644 index 00000000..0c2eddc2 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_footer.tpl @@ -0,0 +1 @@ +</div> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_get_constant_type.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_get_constant_type.tpl new file mode 100644 index 00000000..48301da4 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_get_constant_type.tpl @@ -0,0 +1,10 @@ +{if is_numeric(strtolower(trim($const)))} + int +{elseif strtolower(trim($const)) == "true" || + strtolower(trim($const)) == "false"} + bool +{elseif strtolower(trim($const)) == "null"} + null +{else} + string +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_header.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_header.tpl new file mode 100644 index 00000000..f92571a4 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_header.tpl @@ -0,0 +1,4 @@ +<div id="bar" nowrap="nowrap"> + {include file="_class_list.tpl"} +</div> +<div id="content1"> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_inherited_constants.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_inherited_constants.tpl new file mode 100644 index 00000000..66c37633 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_inherited_constants.tpl @@ -0,0 +1,34 @@ +{if $iconsts} + {section name=iconst loop=$iconsts} + <table class="inherited-constants" cellspacing="1"> + <tr> + <th>Constants Inherited From {$iconsts[iconst].parent_class}</th> + </tr> + <tr> + <td> + {assign var="_consts" value=""} + + {section name=_const loop=$iconsts[iconst].iconsts} + {if $_consts != ""}, + {* append var="_consts" value=", "*} + {/if} + <a href="{$href}">{$iconsts[iconst].iconsts[_const].name}</a>{if !$smarty.section.name.last},{/if} + {* + {extract_attribute attribute="href" + element=$iconsts[iconst].iconsts[_const].link + var="href" append="no"} + + {append var="_consts" value="<a href=\""} + {append var="_consts" value=$href} + {append var="_consts" value="\">"} + {append var="_consts" value=$iconsts[iconst].iconsts[_const].name} + {append var="_consts" value="</a>"} + *} +{/section} + + {*$_consts*} + </td> + </tr> + </table> + {/section} +{/if} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_inherited_methods.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_inherited_methods.tpl new file mode 100644 index 00000000..55aafb17 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_inherited_methods.tpl @@ -0,0 +1,42 @@ +{if $imethods} + {section name=imethod loop=$imethods} + {if count($imethods[imethod].imethods) > 1 || + ($imethods[imethod].imethods[0].name != "__construct" && + $imethods[imethod].imethods[0].name != "__destruct" && + $imethods[imethod].imethods[0].abstract != "1")} + <table class="inherited-methods" cellspacing="1"> + <tr> + <th>Methods Inherited From {$imethods[imethod].parent_class}</th> + </tr> + <tr> + <td> + {* assign var="_methods" value="" *} + + {section name=_method loop=$imethods[imethod].imethods} + {if $imethods[imethod].imethods[_method].name != "__construct" && + $imethods[imethod].imethods[_method].abstract != "1"} + {* + {if $_methods != ""} + {append var="_methods" value=", "} + {/if} + + {extract_attribute attribute="href" + element=$imethods[imethod].imethods[_method].link + var="href" append="no"} + + {append var="_methods" value="<a href=\""} + {append var="_methods" value=$href} + {append var="_methods" value="\">"} + {append var="_methods" value=$imethods[imethod].imethods[_method].name} + {append var="_methods" value="</a>"} + *} + {$imethods[imethod].imethods[_method].link}{if !$smarty.section._method.last},{/if} + {/if} + {/section} + + </td> + </tr> + </table> + {/if} + {/section} +{/if} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_inheritence_tree.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_inheritence_tree.tpl new file mode 100644 index 00000000..471c7972 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_inheritence_tree.tpl @@ -0,0 +1,3 @@ +<div class="inheritence-tree"> + <pre>{section name=tree loop=$class_tree.classes}{if $smarty.section.tree.last}<strong>{$class_tree.classes[tree]}</strong>{else}{$class_tree.classes[tree]}{/if}{$class_tree.distance[tree]}{/section}</pre> +</div> \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_method_details.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_method_details.tpl new file mode 100644 index 00000000..b5ddfb10 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_method_details.tpl @@ -0,0 +1,101 @@ +{if $methods && (count($methods) > 1 || + ($methods[0].function_name != "__construct" && + $methods[0].function_name != "__destruct"))} + + <hr size="1" noshade="noshade"/> + <a name="method-details"></a> + <table class="method-details" cellspacing="1"> + <tr> + <th>Method Details</th> + </tr> + {section name=method loop=$methods} + {if $methods[method].function_name != "__construct" && + $methods[method].function_name != "__destruct"} + + <tr> + <td class="method-data"> + + <a name="{$methods[method].method_dest}"></a> + + <h2>{$methods[method].function_name}</h2> + + <table class="method-detail" cellspacing="0"> + <tr> + <td nowrap="nowrap">{strip} + {if $methods[method].access == "protected"} + protected  + {/if} + + {if $methods[method].access == "public"} + public  + {/if} + + {if $methods[method].abstract == 1} + abstract  + {/if} + + {if $methods[method].static == 1} + static  + {/if} + + {$methods[method].function_return}  + + + <strong>{$methods[method].function_name}</strong> + {/strip}</td> + <td width="100%">{strip} + ( + {if $methods[method].ifunction_call.params} + {foreach item=param name="method" from=$methods[method].ifunction_call.params} + {$param.type} {$param.name} {if !$smarty.foreach.method.last}, {/if} + {/foreach} + + {/if} + ) + {/strip}</td> + </tr> + </table> + + <p>{$methods[method].sdesc}</p> + + {if $methods[method].desc} + {$methods[method].desc} + {/if} + {* $methods[method]|print_r *} + <div class="tag-list"><table class="method-summary" cellspacing="1"> + {if $methods[method].ifunction_call.params} + <tr><th colspan="3" class="small">Input</th></tr> + {foreach item=param name="method" from=$methods[method].ifunction_call.params} + <tr><td valign="top">{$param.type}</td><td valign="top"><strong>{$param.name}</strong><td valign="top">{$param.description}</td></tr> + {/foreach} + {/if} + {if $methods[method].tags} + <tr><th colspan="3" class="small">Output</th></tr> + + {foreach item=param name="method" from=$methods[method].tags} + {if $param.keyword == "return"} + <tr><td valign="top"> + {$methods[method].function_return} + </td><td valign="top" colspan="2">{$param.data}</td></tr> + {/if} + {/foreach} + {/if} + {if $methods[method].tags} + <tr><th colspan="3" class="small">Exception</th></tr> + + {foreach item=param name="method" from=$methods[method].tags} + {if $param.keyword == "throws"} + <tr><td valign="top">{$param.keyword}</td><td valign="top" colspan="2">{$param.data}</td></tr> + {/if} + {/foreach} + {/if} + </table></div> + + {* include file="_tags.tpl" tags=$methods[method].tags *} + <p/> + </td> + </tr> + {/if} + {/section} + </table> +{/if} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_method_summary.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_method_summary.tpl new file mode 100644 index 00000000..8fefd671 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_method_summary.tpl @@ -0,0 +1,61 @@ +{if $methods || $imethods} + <hr size="1" noshade="noshade"/> + <a name="method-summary"></a> + <table class="method-summary" cellspacing="1"> + <tr> + <th colspan="2">Method Summary</th> + </tr> + {section name=method loop=$methods} + {if $methods[method].function_name != "__construct" && + $methods[method].function_name != "__destruct"} + {* + {if trim(substr($methods[method].function_call, 0, 1)) == "&"} + {assign var="ref" value="true"} + {assign var="css" value=" class=\"reference\""} + {else} + {assign var="ref" value="false"} + {assign var="css" value=""} + {/if} + *} + <tr> + <td class="type" nowrap="nowrap" width="1%"> + {if $methods[method].access == "protected"} + protected  + {/if} + + {if $methods[method].abstract == 1} + abstract  + {/if} + + {if $methods[method].static == 1} + static  + {/if} + + {$methods[method].function_return} +{* + {if $ref == "true"} +  & + {/if} +*} + </td> + <td> + <div class="declaration"> + <a href="{$methods[method].id}">{$methods[method].function_name}</a> + ({strip} + {if $methods[method].ifunction_call.params} + {foreach item=param name="method" from=$methods[method].ifunction_call.params} + {$param.type} {$param.name}{if !$smarty.foreach.method.last}, {/if} + {/foreach} + + {/if} + {/strip}) + </div> + <div class="description"> + {$methods[method].sdesc} + </div> + </td> + </tr> + {/if} + {/section} + </table> +{/if} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_sub_classes.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_sub_classes.tpl new file mode 100644 index 00000000..e605b314 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_sub_classes.tpl @@ -0,0 +1,19 @@ +{if $children} + <div class="sub-classes"> + {if $is_interface} + <h4>Direct Known Sub-interfaces:</h4> + {else} + <h4>Direct Known Sub-classes:</h4> + {/if} + + <div><small> + {section name=child loop=$children} + {if !$smarty.section.child.first} + , {$children[child].link} + {else} + {$children[child].link} + {/if} + {/section} + </small></div> + </div> +{/if} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_tags.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_tags.tpl new file mode 100644 index 00000000..221830c4 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/_tags.tpl @@ -0,0 +1,13 @@ +<div class="tag-list"> + {section name=tag loop=$tags} + {if $tags[tag].keyword != "abstract" && + $tags[tag].keyword != "access" && + $tags[tag].keyword != "static" && + $tags[tag].keyword != "version" + } + + <strong>{$tags[tag].keyword|capitalize}:</strong> + {$tags[tag].data}<br /> + {/if} + {/section} +</div> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/basicindex.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/basicindex.tpl new file mode 100644 index 00000000..37e94343 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/basicindex.tpl @@ -0,0 +1,18 @@ +{section name=letter loop=$letters} + [ <a href="{$indexname}.html#{$letters[letter].letter}">{$letters[letter].letter}</a> ] +{/section} + +{section name=index loop=$index} + <hr /> + <a name="{$index[index].letter}"></a> + <div> + <h2>{$index[index].letter}</h2> + <dl> + {section name=contents loop=$index[index].index} + <dt><b>{$index[index].index[contents].name}</b></dt> + <dd>{$index[index].index[contents].listing}</dd> + {/section} + </dl> + </div> + <a href="{$indexname}.html#top">top</a><br> +{/section} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/blank.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/blank.tpl new file mode 100644 index 00000000..b503c142 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/blank.tpl @@ -0,0 +1,5 @@ +<div align="center"><h1>{$maintitle}</h1></div> +<b>Welcome to {$package}!</b><br /> +<br /> +This documentation was generated by <a href="{$phpdocwebsite}">phpDocumentor v{$phpdocversion}</a><br /> + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/class.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/class.tpl new file mode 100644 index 00000000..e791bbba --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/class.tpl @@ -0,0 +1,29 @@ +{include file="header.tpl" eltype="class" hasel=true contents=$classcontents} + +<h1>{if $is_interface}Interface{else}Class{/if} {$class_name}</h1> + +{*inheritence tree*} +<div class="inheritence-tree"> + <pre>{section name=tree loop=$class_tree.classes}{if $smarty.section.tree.last}<strong>{$class_tree.classes[tree]}</strong>{else}{$class_tree.classes[tree]}{/if}{$class_tree.distance[tree]}{/section}</pre> +</div> + +{include file="_sub_classes.tpl"} +{include file="_class_description.tpl"} +{include file="_inherited_constants.tpl"} + +{include file="_constructor_summary.tpl"} +{* include file="_destructor_summary.tpl" *} + +{include file="_method_summary.tpl"} + +{include file="_inherited_methods.tpl"} +{include file="_constant_summary.tpl"} +{include file="_constructor_details.tpl"} + +{* include file="_destructor_details.tpl" *} + +{include file="_method_details.tpl"} + +{include file="_constant_details.tpl"} + +{include file="footer.tpl"} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/classleft.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/classleft.tpl new file mode 100644 index 00000000..c07fc33a --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/classleft.tpl @@ -0,0 +1,9 @@ +{foreach key=subpackage item=files from=$classleftindex} + <div class="package"> + {if $subpackage != ""}{$subpackage}<br />{/if} + {section name=files loop=$files} + {if $subpackage != ""}  {/if} + {if $files[files].link != ''}<a href="{$files[files].link}">{/if}{$files[files].title}{if $files[files].link != ''}</a>{/if}<br /> + {/section} + </div> +{/foreach} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/classtrees.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/classtrees.tpl new file mode 100644 index 00000000..4020e3a8 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/classtrees.tpl @@ -0,0 +1,8 @@ +{include file="header.tpl" noleftindex=true} +<h1>{$title}</h1> +{section name=classtrees loop=$classtrees} +<hr /> +<div class="classtree">Root class {$classtrees[classtrees].class}</div><br> +{$classtrees[classtrees].class_tree} +{/section} +{include file="footer.tpl"} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/const.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/const.tpl new file mode 100644 index 00000000..88856c4b --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/const.tpl @@ -0,0 +1,14 @@ +{section name=consts loop=$consts} +{if $show == 'summary'} + var {$consts[consts].const_name}, {$consts[consts].sdesc}<br> +{else} + <a name="{$consts[consts].const_dest}"></a> + <p></p> + <h4>{$consts[consts].const_name} = <span class="value">{$consts[consts].const_value|replace:"\n":"<br>\n"|replace:" ":" "|replace:"\t":"   "}</span></h4> + <p>[line {if $consts[consts].slink}{$consts[consts].slink}{else}{$consts[consts].line_number}{/if}]</p> + {include file="docblock.tpl" sdesc=$consts[consts].sdesc desc=$consts[consts].desc tags=$consts[consts].tags} + + <br /> + <div class="top">[ <a href="#top">Top</a> ]</div><br /> +{/if} +{/section} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/define.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/define.tpl new file mode 100644 index 00000000..04ce5b48 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/define.tpl @@ -0,0 +1,32 @@ +{if count($defines) > 0} +{section name=def loop=$defines} +{if $show == 'summary'} +define constant <a href="{$defines[def].id}">{$defines[def].define_name}</a> = {$defines[def].define_value}, {$defines[def].sdesc}<br> +{else} + <hr /> + <a name="{$defines[def].define_link}"></a> + <h3>{$defines[def].define_name} <span class="smalllinenumber">[line {if $defines[def].slink}{$defines[def].slink}{else}{$defines[def].line_number}{/if}]</span></h3> + <div class="tags"> + <table width="90%" border="0" cellspacing="0" cellpadding="1"><tr><td class="code_border"> + <table width="100%" border="0" cellspacing="0" cellpadding="2"><tr><td class="code"> + <code>{$defines[def].define_name} = {$defines[def].define_value}</code> + </td></tr></table> + </td></tr></table> + + {include file="docblock.tpl" sdesc=$defines[def].sdesc desc=$defines[def].desc tags=$defines[def].tags} + <br /> + {if $defines[def].define_conflicts.conflict_type} + <p><b>Conflicts with defines:</b> + {section name=me loop=$defines[def].define_conflicts.conflicts} + {$defines[def].define_conflicts.conflicts[me]}<br /> + {/section} + </p> + {/if} +{* original {if $defines[def].define_conflicts != "" + <b>Conflicts:</b> {$defines[def].define_conflicts<br /><br /> + {/if *} + </div> + <div class="top">[ <a href="#top">Top</a> ]</div><br /><br /> +{/if} +{/section} +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/docblock.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/docblock.tpl new file mode 100644 index 00000000..09a603f8 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/docblock.tpl @@ -0,0 +1,15 @@ +{if $sdesc != ''}{$sdesc|default:''}<br /><br />{/if} +{if $desc != ''}{$desc|default:''}<br />{/if} +{if count($tags) > 0} +<br /><br /> +<h4>Tags:</h4> +<div class="tags"> +<table border="0" cellspacing="0" cellpadding="0"> +{section name=tag loop=$tags} + <tr> + <td><b>{$tags[tag].keyword}:</b>  </td><td>{$tags[tag].data}</td> + </tr> +{/section} +</table> +</div> +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/elementindex.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/elementindex.tpl new file mode 100644 index 00000000..175a5136 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/elementindex.tpl @@ -0,0 +1,5 @@ +{include file="header.tpl" noleftindex=true} +<a name="top"></a> +<h1>Index of all elements</h1> +{include file="basicindex.tpl" indexname="elementindex"} +{include file="footer.tpl"} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/errors.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/errors.tpl new file mode 100644 index 00000000..1576a822 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/errors.tpl @@ -0,0 +1,21 @@ +{include file="header.tpl" noleftindex=true} +{section name=files loop=$files} +<a href="#{$files[files].file}">{$files[files].file}</a><br> +{/section} +{foreach key=file item=issues from=$all} +<a name="{$file}"></a> +<h1>{$file}</h1> +{if count($issues.warnings)} +<h2>Warnings:</h2><br> +{section name=warnings loop=$issues.warnings} +<b>{$issues.warnings[warnings].name}</b> - {$issues.warnings[warnings].listing}<br> +{/section} +{/if} +{if count($issues.errors)} +<h2>Errors:</h2><br> +{section name=errors loop=$issues.errors} +<b>{$issues.errors[errors].name}</b> - {$issues.errors[errors].listing}<br> +{/section} +{/if} +{/foreach} +{include file="footer.tpl"} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/examplesource.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/examplesource.tpl new file mode 100644 index 00000000..fb85654b --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/examplesource.tpl @@ -0,0 +1,6 @@ +{include file="header.tpl" title=$title} +<h1 align="center">{$title}</h1> +<div class="php"> +{$source} +</div> +{include file="footer.tpl"} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/fileleft.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/fileleft.tpl new file mode 100644 index 00000000..50f108d7 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/fileleft.tpl @@ -0,0 +1,10 @@ +{foreach key=subpackage item=files from=$fileleftindex} + {if $subpackage != ""}subpackage <b>{$subpackage}</b><br>{/if} + <div class="package"> + {section name=files loop=$files} + {if $files[files].link != ''}<a href="{$files[files].link}">{/if} + {$files[files].title} + {if $files[files].link != ''}</a>{/if}<br> + {/section} + </div><br /> +{/foreach} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/filesource.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/filesource.tpl new file mode 100644 index 00000000..b23076a0 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/filesource.tpl @@ -0,0 +1,8 @@ +{capture name="tutle"}File Source for {$name}{/capture} +{include file="header.tpl" title=$smarty.capture.tutle} +<h1 align="center">Source for file {$name}</h1> +<p>Documentation is available at {$docs}</p> +<div class="php"> +{$source} +</div> +{include file="footer.tpl"} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/footer.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/footer.tpl new file mode 100644 index 00000000..0bb7a7dd --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/footer.tpl @@ -0,0 +1,25 @@ + <!-- content end --></td></tr></table> + </td> + </tr> +</table> + +</div><!-- main --> + +<div id="footer"> + <a href="/tos/">Terms of Service</a> | + <a href="/support/">Contact Us</a> + <br/> + Copyright © 2006 by Prado Software Group.<br/> + <a title="Powered by PRADO" href="http://www.pradosoft.com/"><img src="http://www.pradosoft.com/images/powered.gif" style="border-width:0px;" alt="Powered by PRADO" /></a> +</div> + +</div><!-- page --> +<script src="http://www.google-analytics.com/urchin.js" type="text/javascript"> +</script> +<script type="text/javascript"> +_uacct = "UA-186303-3"; +urchinTracker(); +</script> + +</body> +</html> \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/function.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/function.tpl new file mode 100644 index 00000000..098aeb17 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/function.tpl @@ -0,0 +1,48 @@ +{section name=func loop=$functions} +{if $show == 'summary'} +function {$functions[func].id}, {$functions[func].sdesc}<br /> +{else} + <hr /> + <a name="{$functions[func].function_dest}"></a> + <h3>{$functions[func].function_name} <span class="smalllinenumber">[line {if $functions[func].slink}{$functions[func].slink}{else}{$functions[func].line_number}{/if}]</span></h3> + <div class="function"> + <table width="90%" border="0" cellspacing="0" cellpadding="1"><tr><td class="code_border"> + <table width="100%" border="0" cellspacing="0" cellpadding="2"><tr><td class="code"> + <code>{$functions[func].function_return} {if $functions[func].ifunction_call.returnsref}&{/if}{$functions[func].function_name}( +{if count($functions[func].ifunction_call.params)} +{section name=params loop=$functions[func].ifunction_call.params} +{if $smarty.section.params.iteration != 1}, {/if}{if $functions[func].ifunction_call.params[params].default != ''}[{/if}{$functions[func].ifunction_call.params[params].type} {$functions[func].ifunction_call.params[params].name}{if $functions[func].ifunction_call.params[params].default != ''} = {$functions[func].ifunction_call.params[params].default|escape:"html"}]{/if} +{/section} +{/if})</code> + </td></tr></table> + </td></tr></table><br /> + + {include file="docblock.tpl" sdesc=$functions[func].sdesc desc=$functions[func].desc tags=$functions[func].tags} + <br /><br /> + {if $functions[func].function_conflicts.conflict_type} + <p><b>Conflicts with functions:</b> + {section name=me loop=$functions[func].function_conflicts.conflicts} + {$functions[func].function_conflicts.conflicts[me]}<br /> + {/section} + </p> + {/if} +{* original {if $functions[func].function_conflicts != "" + <b>Conflicts:</b> {$functions[func].function_conflicts<br /><br /> + {/if *} + + {if count($functions[func].params) > 0} + <h4>Parameters</h4> + <table border="0" cellspacing="0" cellpadding="0"> + {section name=params loop=$functions[func].params} + <tr> + <td class="type">{$functions[func].params[params].datatype}  </td> + <td><b>{$functions[func].params[params].var}</b>  </td> + <td>{$functions[func].params[params].data}</td> + </tr> + {/section} + </table> + {/if} + <div class="top">[ <a href="#top">Top</a> ]</div><br /><br /> + </div> +{/if} +{/section} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/global.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/global.tpl new file mode 100644 index 00000000..1053f748 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/global.tpl @@ -0,0 +1,40 @@ +{if count($globals) > 0} +{section name=glob loop=$globals} +{if $show == 'summary'} +global variable <a href="{$globals[glob].id}">{$globals[glob].global_name}</a> = {$globals[glob].global_value}, {$globals[glob].sdesc}<br> +{else} + <hr /> + <a name="{$globals[glob].global_link}"></a> + <h4><i>{$globals[glob].global_type}</i> {$globals[glob].global_name} <span class="smalllinenumber">[line {if $globals[glob].slink}{$globals[glob].slink}{else}{$globals[glob].line_number}{/if}]</span></h4> + <div class="tags"> + {if $globals[glob].sdesc != ""} + {include file="docblock.tpl" sdesc=$globals[glob].sdesc desc=$globals[glob].desc tags=$globals[glob].tags} + {/if} + + <table border="0" cellspacing="0" cellpadding="0"> + <tr> + <td><b>Default value:</b>  </td> + <td>{$globals[glob].global_value|replace:" ":" "|replace:"\n":"<br />\n"|replace:"\t":"   "}</td> + </tr> + {if $globals[glob].global_conflicts.conflict_type} + <tr> + <td><b>Conflicts with globals:</b>  </td> + <td> + {section name=me loop=$globals[glob].global_conflicts.conflicts} + {$globals[glob].global_conflicts.conflicts[me]}<br /> + {/section} + </td> + </tr> + {/if} +{* original {if $globals[glob].global_conflicts != "" + <tr> + <td><b>Conflicts:</b>  </td> + <td>{$globals[glob].global_conflicts</td> + </tr> + {/if *} + </table> + </div><br /><br /> + <div class="top">[ <a href="#top">Top</a> ]</div><br /><br /> +{/if} +{/section} +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/header.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/header.tpl new file mode 100644 index 00000000..b35b0f57 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/header.tpl @@ -0,0 +1,121 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" > + +<head> +<title>PRADO API Manual: {$title} + + + + + + + + + + + + + + + + + +
        + + + +
        + + + + + + + + + + a + b + + + + + + + + diff --git a/buildscripts/phing/etc/phpunit2-frames.xsl b/buildscripts/phing/etc/phpunit2-frames.xsl new file mode 100644 index 00000000..7ccc4f33 --- /dev/null +++ b/buildscripts/phing/etc/phpunit2-frames.xsl @@ -0,0 +1,677 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unit Test Results. + + + + + + + + + <h2>Frame Alert</h2> + <p> + This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. + </p> + + + + + + + +body { + font-family: verdana,arial,helvetica; + color:#000000; + font-size: 12px; +} +table tr td, table tr th { + font-family: verdana,arial,helvetica; + font-size: 12px; +} +table.details tr th{ + font-family: verdana,arial,helvetica; + font-weight: bold; + text-align:left; + background:#a6caf0; +} +table.details tr td{ + background:#eeeee0; +} + +p { + line-height:1.5em; + margin-top:0.5em; margin-bottom:1.0em; + font-size: 12px; +} +h1 { + margin: 0px 0px 5px; + font-family: verdana,arial,helvetica; +} +h2 { + margin-top: 1em; margin-bottom: 0.5em; + font-family: verdana,arial,helvetica; +} +h3 { + margin-bottom: 0.5em; + font-family: verdana,arial,helvetica; +} +h4 { + margin-bottom: 0.5em; + font-family: verdana,arial,helvetica; +} +h5 { + margin-bottom: 0.5em; + font-family: verdana,arial,helvetica; +} +h6 { + margin-bottom: 0.5em; + font-family: verdana,arial,helvetica; +} +.Error { + font-weight:bold; color:red; +} +.Failure { + font-weight:bold; color:purple; +} +.small { + font-size: 9px; +} +a { + color: #003399; +} +a:hover { + color: #888888; +} + + + + + + + . + + + Unit Test Results: <xsl:value-of select="$class.name"/> + + + + + + +

        Class

        + + +
        +{if count($ric) >= 1} +
        + {section name=ric loop=$ric} +

        {$ric[ric].name}

        + {/section} +
        +{/if} + Packages:
        + {section name=packagelist loop=$packageindex} + {$packageindex[packagelist].title}
        + {/section} +

        +{if $tutorials} + Tutorials/Manuals:
        + {if $tutorials.pkg} + Package-level: + {section name=ext loop=$tutorials.pkg} + {$tutorials.pkg[ext]} + {/section} + {/if} + {if $tutorials.cls} + Class-level: + {section name=ext loop=$tutorials.cls} + {$tutorials.cls[ext]} + {/section} + {/if} + {if $tutorials.proc} + Procedural-level: + {section name=ext loop=$tutorials.proc} + {$tutorials.proc[ext]} + {/section} + {/if} +{/if} + {if !$noleftindex}{assign var="noleftindex" value=false}{/if} + {if !$noleftindex} +{* +{if $compiledfileindex} + Files:
        + {eval var=$compiledfileindex} + {/if} +*} + {if $compiledclassindex} + Classes:
        + {eval var=$compiledclassindex} + {/if} + {/if} +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ../ + + + + + + ../ + + + + + + + + stylesheet.css + + + + + + a + b + + + + + + diff --git a/buildscripts/phing/etc/log.xsl b/buildscripts/phing/etc/log.xsl new file mode 100644 index 00000000..a460b667 --- /dev/null +++ b/buildscripts/phing/etc/log.xsl @@ -0,0 +1,216 @@ + + + + + + + + + + + Phing Build Log + + + + +
        +
        + Keyword + +
        +
        +{* +{if !$hasel}{assign var="hasel" value=false}{/if} +{if $hasel} +

        {$eltype|capitalize}: {$class_name}

        +Source Location: {$source_location}

        +{/if} +*} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/include.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/include.tpl new file mode 100644 index 00000000..cff067db --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/include.tpl @@ -0,0 +1,9 @@ +{if count($includes) > 0} +

        Includes:

        +
        +{section name=includes loop=$includes} +{$includes[includes].include_name}({$includes[includes].include_value}) [line {if $includes[includes].slink}{$includes[includes].slink}{else}{$includes[includes].line_number}{/if}]
        +{include file="docblock.tpl" sdesc=$includes[includes].sdesc desc=$includes[includes].desc tags=$includes[includes].tags} +{/section} +
        +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/index.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/index.tpl new file mode 100644 index 00000000..60c74b47 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/index.tpl @@ -0,0 +1,7 @@ +{include file="header.tpl"} +{if $contents} +{$contents} +{else} +{include file="blank.tpl"} +{/if} +{include file="footer.tpl"} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/media/background.png b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/media/background.png new file mode 100644 index 00000000..d6f36f60 Binary files /dev/null and b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/media/background.png differ diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/media/empty.png b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/media/empty.png new file mode 100644 index 00000000..a9f29bb1 Binary files /dev/null and b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/media/empty.png differ diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/media/style.css b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/media/style.css new file mode 100644 index 00000000..9419ca62 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/media/style.css @@ -0,0 +1,197 @@ +.php { + padding: 1em; +} +/* This will not be executed by IE, so now we have a fix! */ +*[class="php-src"], *[class="php"], *[class="listing"] { + line-height: 0px; +} + +body +{ + color: #000000; + background-color: #ffffff; + background-image: url("background.png"); + background-repeat: repeat-y; + font-family: tahoma, verdana, arial, sans-serif; + font-size: 10pt; + margin: 0; + padding: 0; +} + +a +{ + color: #000099; + background-color: transparent; + text-decoration: none; +} + +a:hover +{ + text-decoration: underline; +} + +a.menu +{ + color: #ffffff; + background-color: transparent; +} + +td +{ + font-size: 10pt; +} + +td.header_top +{ + color: #ffffff; + background-color: #9999cc; + font-size: 16pt; + font-weight: bold; + text-align: right; + padding: 10px; +} + +td.header_line +{ + color: #ffffff; + background-color: #333366; +} + +td.header_menu +{ + color: #ffffff; + background-color: #666699; + font-size: 8pt; + text-align: right; + padding: 2px; + padding-right: 5px; +} + +td.menu +{ + padding: 2px; + padding-left: 5px; +} + +td.code_border +{ + color: #000000; + background-color: #c0c0c0; +} + +td.code +{ + color: #000000; + background-color: #f0f0f0; +} + +td.type +{ + font-style: italic; +} + +div.credit +{ + font-size: 8pt; + text-align: center; +} + +div.package +{ + padding-left: 5px; +} + +div.tags +{ + padding-left: 15px; +} + +div.function +{ + padding-left: 15px; +} + +div.top +{ + font-size: 8pt; +} + +div.warning +{ + color: #ff0000; + background-color: transparent; +} + +div.description +{ + padding-left: 15px; +} + +hr +{ + height: 1px; + border-style: solid; + border-color: #c0c0c0; + margin-top: 10px; + margin-bottom: 10px; +} + +span.smalllinenumber +{ + font-size: 8pt; +} + +ul { + margin-left: 0px; + padding-left: 8px; +} +/* Syntax highlighting */ + +.src-code { background-color: #f5f5f5; border: 1px solid #ccc9a4; padding: 0px; margin : 0px} +/*.src-code pre { }*/ + +.src-comm { color: green; } +.src-id { } +.src-inc { color: #0000FF; } +.src-key { color: #0000FF; } +.src-num { color: #CC0000; } +.src-str { color: #66cccc; } +.src-sym { font-weight: bold; } +.src-var { } + +.src-php { font-weight: bold; } + +.src-doc { color: #009999 } +.src-doc-close-template { color: #0000FF } +.src-doc-coretag { color: #0099FF; font-weight: bold } +.src-doc-inlinetag { color: #0099FF } +.src-doc-internal { color: #6699cc } +.src-doc-tag { color: #0080CC } +.src-doc-template { color: #0000FF } +.src-doc-type { font-style: italic } +.src-doc-var { font-style: italic } + +.tute-tag { color: #009999 } +.tute-attribute-name { color: #0000FF } +.tute-attribute-value { color: #0099FF } +.tute-entity { font-weight: bold; } +.tute-comment { font-style: italic } +.tute-inline-tag { color: #636311; font-weight: bold } + +/* tutorial */ + +.authors { } +.author { font-style: italic; font-weight: bold } +.author-blurb { margin: .5em 0em .5em 2em; font-size: 85%; font-weight: normal; font-style: normal } +.example { border: 1px dashed #999999; background-color: #EEEEEE; padding: .5em; } +.listing { border: 1px dashed #999999; background-color: #EEEEEE; padding: .5em; white-space: nowrap; } +.release-info { font-size: 85%; font-style: italic; margin: 1em 0em } +.ref-title-box { } +.ref-title { } +.ref-purpose { font-style: italic; color: #666666 } +.ref-synopsis { } +.title { font-weight: bold; margin: 1em 0em 0em 0em; padding: .25em; border: 2px solid #999999; background-color: #9999CC } +.cmd-synopsis { margin: 1em 0em } +.cmd-title { font-weight: bold } +.toc { margin-left: 2em; padding-left: 0em } + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/method.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/method.tpl new file mode 100644 index 00000000..07cb76e5 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/method.tpl @@ -0,0 +1,58 @@ +{section name=methods loop=$methods} +{if $show == 'summary'} +method {$methods[methods].function_call}, {$methods[methods].sdesc}
        +{else} +
        + +

        {if $methods[methods].ifunction_call.constructor}constructor {elseif $methods[methods].ifunction_call.destructor}destructor {else}method {/if}{$methods[methods].function_name} [line {if $methods[methods].slink}{$methods[methods].slink}{else}{$methods[methods].line_number}{/if}]

        +
        +
        +
        + {$methods[methods].function_return} {if $methods[methods].ifunction_call.returnsref}&{/if}{$methods[methods].function_name}( +{if count($methods[methods].ifunction_call.params)} +{section name=params loop=$methods[methods].ifunction_call.params} +{if $smarty.section.params.iteration != 1}, {/if} +{if $methods[methods].ifunction_call.params[params].default != ''}[{/if}{$methods[methods].ifunction_call.params[params].type} +{$methods[methods].ifunction_call.params[params].name}{if $methods[methods].ifunction_call.params[params].default != ''} = {$methods[methods].ifunction_call.params[params].default}]{/if} +{/section} +{/if}) +
        +

        + + {include file="docblock.tpl" sdesc=$methods[methods].sdesc desc=$methods[methods].desc tags=$methods[methods].tags}

        + +{if $methods[methods].descmethod} +

        Overridden in child classes as:
        + {section name=dm loop=$methods[methods].descmethod} +

        +
        {$methods[methods].descmethod[dm].link}
        +
        {$methods[methods].descmethod[dm].sdesc}
        +
        + {/section}

        +{/if} +{* original {if $methods[methods].descmethod != "" + {$methods[methods].descmethod

        + {/if *} +{if $methods[methods].method_overrides}Overrides {$methods[methods].method_overrides.link} ({$methods[methods].method_overrides.sdesc|default:"parent method not documented"})

        {/if} +{* original {if $methods[methods].method_overrides != "" + {$methods[methods].method_overrides

        + {/if *} + + {if count($methods[methods].params) > 0} +

        Parameters:

        +
        + + {section name=params loop=$methods[methods].params} + + + + + + {/section} +
        {$methods[methods].params[params].datatype}  {$methods[methods].params[params].var}  {$methods[methods].params[params].data}
        +

        + {/if} +
        [ Top ]
        +
        +{/if} +{/section} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/packages.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/packages.tpl new file mode 100644 index 00000000..b48b6719 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/packages.tpl @@ -0,0 +1,3 @@ +{section name=packages loop=$packages} +{$packages[packages].title} +{/section} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/page.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/page.tpl new file mode 100644 index 00000000..6dd8683d --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/page.tpl @@ -0,0 +1,31 @@ +{include file="header.tpl" eltype="Procedural file" class_name=$name hasel=true contents=$pagecontents} + +
        +
        + +{if $classes} +
        +{if $tutorial} +Main Tutorial: {$tutorial} +{/if} +

        Classes:

        +{section name=classes loop=$classes} +
        {$classes[classes].link}
        +
        {$classes[classes].sdesc}
        +{/section} +


        +{/if} + +

        Page Details:

        +{include file="docblock.tpl" type="page"} +

        +{include file="include.tpl"} +

        +{include file="global.tpl"} +

        +{include file="define.tpl"} +
        +{include file="function.tpl"} + +{include file="footer.tpl"} + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/pkgelementindex.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/pkgelementindex.tpl new file mode 100644 index 00000000..753ad7cf --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/pkgelementindex.tpl @@ -0,0 +1,5 @@ +{include file="header.tpl"} + +

        Element index for package {$package}

        +{include file="basicindex.tpl" indexname=elementindex_$package} +{include file="footer.tpl"} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/ric.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/ric.tpl new file mode 100644 index 00000000..c4cb83f9 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/ric.tpl @@ -0,0 +1,6 @@ +{include file="header.tpl"} +

        {$name}

        +
        +{$contents|htmlentities}
        +
        +{include file="footer.tpl"} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/todolist.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/todolist.tpl new file mode 100644 index 00000000..5ab0bca2 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/todolist.tpl @@ -0,0 +1,14 @@ +{include file="header.tpl" title="Todo List"} +

        Todo List

        +{foreach from=$todos key=todopackage item=todo} +

        {$todopackage}

        +{section name=todo loop=$todo} +

        {$todo[todo].link}

        +
          +{section name=t loop=$todo[todo].todos} +
        • {$todo[todo].todos[t]}
        • +{/section} +
        +{/section} +{/foreach} +{include file="footer.tpl"} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/tutorial.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/tutorial.tpl new file mode 100644 index 00000000..22c71c3b --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/tutorial.tpl @@ -0,0 +1,32 @@ +{include file="header.tpl" title=$title} +{if $nav} + + + + + + +
        {if $prev}{/if}Prev{if $prev}{/if}{if $next}{/if}Next{if $next}{/if}
        +{/if} +{$contents} +{if $nav} + + + + + + + + + + + + +
        {if $prev}{/if} +Prev{if $prev}{/if}{if $up}Up{else} {/if}{if $next}{/if}Next{if $next}{/if}
        {if $prevtitle}{$prevtitle}{/if}{if $uptitle}{$uptitle}{/if}{if $nexttitle}{$nexttitle}{/if}
        +{/if} +{include file="footer.tpl"} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/tutorial_toc.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/tutorial_toc.tpl new file mode 100644 index 00000000..1db34438 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/tutorial_toc.tpl @@ -0,0 +1,29 @@ +{if count($toc)} +

        Table of Contents

        +
          +{section name=toc loop=$toc} +{if $toc[toc].tagname == 'refsect1'} +{assign var="context" value="refsect1"} +{$toc[toc].link}
          +{/if} +{if $toc[toc].tagname == 'refsect2'} +{assign var="context" value="refsect2"} +   {$toc[toc].link}
          +{/if} +{if $toc[toc].tagname == 'refsect3'} +{assign var="context" value="refsect3"} +      {$toc[toc].link}
          +{/if} +{if $toc[toc].tagname == 'table'} +{if $context == 'refsect2'}   {/if} +{if $context == 'refsect3'}   {/if} +Table: {$toc[toc].link} +{/if} +{if $toc[toc].tagname == 'example'} +{if $context == 'refsect2'}   {/if} +{if $context == 'refsect3'}   {/if} +Table: {$toc[toc].link} +{/if} +{/section} +
        +{/if} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/tutorial_tree.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/tutorial_tree.tpl new file mode 100644 index 00000000..faf7bcef --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/tutorial_tree.tpl @@ -0,0 +1,5 @@ + + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/var.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/var.tpl new file mode 100644 index 00000000..c76929fe --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/Smarty/templates/PradoSoft/templates/var.tpl @@ -0,0 +1,28 @@ +{section name=vars loop=$vars} +{if $show == 'summary'} + var {$vars[vars].var_name}, {$vars[vars].sdesc}
        +{else} + +

        +

        {$vars[vars].var_name} = {$vars[vars].var_default|replace:"\n":"
        \n"|replace:" ":" "|replace:"\t":"   "}

        +

        [line {if $vars[vars].slink}{$vars[vars].slink}{else}{$vars[vars].line_number}{/if}]

        + {include file="docblock.tpl" sdesc=$vars[vars].sdesc desc=$vars[vars].desc tags=$vars[vars].tags} + +
        +
        + + + + + + {if $vars[vars].var_overrides != ""} + + + + + {/if} +
        Type:  {$vars[vars].var_type}
        Overrides:  {$vars[vars].var_overrides}
        +


        +
        [ Top ]

        +{/if} +{/section} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/HTMLframesConverter.inc b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/HTMLframesConverter.inc new file mode 100644 index 00000000..d1b8751c --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/HTMLframesConverter.inc @@ -0,0 +1,1747 @@ + + * @since 1.0rc1 + * @version $Id: HTMLframesConverter.inc,v 1.1 2005/10/17 18:37:03 jeichorn Exp $ + */ +/** + * HTML output converter. + * This Converter takes output from the {@link Parser} and converts it to HTML-ready output for use with {@link Smarty}. + * + * @package Converters + * @subpackage HTMLframes + * @see parserDocBlock, parserInclude, parserPage, parserClass, parserDefine, parserFunction, parserMethod, parserVar + * @author Greg Beaver + * @since 1.2 + * @version $Id: HTMLframesConverter.inc,v 1.1 2005/10/17 18:37:03 jeichorn Exp $ + */ +class HTMLframesConverter extends Converter +{ + /** + * Smarty Converter wants elements sorted by type as well as alphabetically + * @see Converter::$sort_page_contents_by_type + * @var boolean + */ + var $sort_page_contents_by_type = true; + /** @var string */ + var $outputformat = 'HTML'; + /** @var string */ + var $name = 'frames'; + /** + * indexes of elements by package that need to be generated + * @var array + */ + var $leftindex = array('classes' => true, 'pages' => true, 'functions' => true, 'defines' => false, 'globals' => false); + + /** + * output directory for the current procedural page being processed + * @var string + */ + var $page_dir; + + /** + * target directory passed on the command-line. + * {@link $targetDir} is malleable, always adding package/ and package/subpackage/ subdirectories onto it. + * @var string + */ + var $base_dir; + + /** + * output directory for the current class being processed + * @var string + */ + var $class_dir; + + /** + * array of converted package page names. + * Used to link to the package page in the left index + * @var array Format: array(package => 1) + */ + var $package_pages = array(); + + /** + * controls formatting of parser informative output + * + * Converter prints: + * "Converting /path/to/file.php... Procedural Page Elements... Classes..." + * Since HTMLdefaultConverter outputs files while converting, it needs to send a \n to start a new line. However, if there + * is more than one class, output is messy, with multiple \n's just between class file output. This variable prevents that + * and is purely cosmetic + * @var boolean + */ + var $juststarted = false; + + /** + * contains all of the template procedural page element loop data needed for the current template + * @var array + */ + var $current; + + /** + * contains all of the template class element loop data needed for the current template + * @var array + */ + var $currentclass; + var $wrote = false; + var $ric_set = array(); + + /** + * sets {@link $base_dir} to $targetDir + * @see Converter() + */ + function HTMLframesConverter(&$allp, &$packp, &$classes, &$procpages, $po, $pp, $qm, $targetDir, $templateDir, $title) + { + Converter::Converter($allp, $packp, $classes, $procpages,$po, $pp, $qm, $targetDir, $templateDir, $title); + $this->base_dir = $targetDir; + } + + /** + * @deprecated in favor of PHP 4.3.0+ tokenizer-based source highlighting + */ + function unmangle($sourcecode) + { + $sourcecode = str_replace('','
        ',$sourcecode);
        +        $sourcecode = str_replace('','
        ',$sourcecode); + $sourcecode = str_replace('
        ',"\n",$sourcecode); + $sourcecode = str_replace(' ',' ',$sourcecode); + $sourcecode = str_replace('<','<',$sourcecode); + $sourcecode = str_replace('>','>',$sourcecode); + $sourcecode = str_replace('&','&',$sourcecode); + return $sourcecode; + } + + /** + * @param string full path to the source file + * @param string fully highlighted source code + */ + function writeSource($path, $value) + { + $templ = &$this->newSmarty(); + $pathinfo = $this->proceduralpages->getPathInfo($path, $this); + $templ->assign('source',$value); + $templ->assign('package',$pathinfo['package']); + $templ->assign('subpackage',$pathinfo['subpackage']); + $templ->assign('name',$pathinfo['name']); + $templ->assign('source_loc',$pathinfo['source_loc']); + $templ->assign('docs',$pathinfo['docs']); + $templ->assign("subdir",'../'); + $templ->register_outputfilter('HTMLframes_outputfilter'); + $this->setTargetDir($this->getFileSourcePath($this->base_dir)); + phpDocumentor_out("\n"); + $this->setSourcePaths($path); + $this->writefile($this->getFileSourceName($path).'.html',$templ->fetch('filesource.tpl')); + } + + function writeExample($title, $path, $source) + { + $templ = &$this->newSmarty(); + $templ->assign('source',$source); + if (empty($title)) + { + $title = 'example'; + addWarning(PDERROR_EMPTY_EXAMPLE_TITLE, $path, $title); + } + $templ->assign('title',$title); + $templ->assign('file',$path); + $templ->assign("subdir",'../'); + $templ->register_outputfilter('HTMLframes_outputfilter'); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . '__examplesource'); + phpDocumentor_out("\n"); + $this->writefile('exsource_'.$path.'.html',$templ->fetch('examplesource.tpl')); + } + + function getExampleLink($path, $title) + { + return $this->returnLink('{$subdir}__examplesource' . PATH_DELIMITER . 'exsource_'.$path.'.html',$title); + } + + function getSourceLink($path) + { + return $this->returnLink($this->getFileSourcePath('{$subdir}') . + PATH_DELIMITER . $this->getFileSourceName($path).'.html','Source Code for this file'); + } + + /** + * Return a line of highlighted source code with formatted line number + * + * If the $path is a full path, then an anchor to the line number will be + * added as well + * @param integer line number + * @param string highlighted source code line + * @param false|string full path to @filesource file this line is a part of, + * if this is a single line from a complete file. + * @return string formatted source code line with line number + */ + function sourceLine($linenumber, $line, $path = false) + { + $extra = ''; + if (strlen(str_replace("\n", '', $line)) == 0) { + $extra = ' '; + } + if ($path) + { + return '
      • ' . $this->getSourceAnchor($path, $linenumber) . + str_replace("\n",'',$line) . $extra . + "
      • \n"; + } else + { + return '
      • ' . str_replace("\n",'',$line) . "$extra
      • \n"; + } + } + + /** + * Used to convert the <> tag in a docblock + * @param string + * @param boolean + * @return string + */ + function ProgramExample($example, $tutorial = false, $inlinesourceparse = null/*false*/, + $class = null/*false*/, $linenum = null/*false*/, $filesourcepath = null/*false*/) + { + return '
          ' . parent::ProgramExample($example, $tutorial, $inlinesourceparse, $class, $linenum, $filesourcepath) + .'
        '; + } + + /** + * @param string + */ + function TutorialExample($example) + { + $trans = $this->template_options['desctranslate']; + $this->template_options['desctranslate'] = array(); + $example = '
          ' . parent::TutorialExample($example) + .'
        '; + $this->template_options['desctranslate'] = $trans; + if (!isset($this->template_options['desctranslate'])) return $example; + if (!isset($this->template_options['desctranslate']['code'])) return $example; + $example = $this->template_options['desctranslate']['code'] . $example; + if (!isset($this->template_options['desctranslate']['/code'])) return $example; + return $example . $this->template_options['desctranslate']['/code']; + } + + /** + * Retrieve a Converter-specific anchor to a segment of a source code file + * parsed via a {@tutorial tags.filesource.pkg} tag. + * @param string full path to source file + * @param string name of anchor + * @param string link text, if this is a link + * @param boolean returns either a link or a destination based on this + * parameter + * @return string link to an anchor, or the anchor + */ + function getSourceAnchor($sourcefile,$anchor,$text = '',$link = false) + { + if ($link) + return $this->returnLink($this->getFileSourcePath('{$subdir}') . + PATH_DELIMITER . $this->getFileSourceName($sourcefile).'.html#a'.$anchor, $text); + else + return ''; + } + + function getCurrentPageLink() + { + return $this->curname . '.html'; + } + + /** + * Uses htmlspecialchars() on the input + */ + function postProcess($text) + { + return htmlspecialchars($text); + } + + /** + * Use the template tutorial_toc.tpl to generate a table of contents for HTML + * @return string table of contents formatted for use in the current output format + * @param array format: array(array('tagname' => section, 'link' => returnsee link, 'id' => anchor name, 'title' => from title tag),...) + */ + function formatTutorialTOC($toc) + { + $template = &$this->newSmarty(); + $template->assign('toc',$toc); + return $template->fetch('tutorial_toc.tpl'); + } + + function &SmartyInit(&$templ) + { + if (!isset($this->package_index)) + foreach($this->all_packages as $key => $val) + { + if (isset($this->pkg_elements[$key])) + { + if (!isset($start)) $start = $key; + $this->package_index[] = array('link' => "li_$key.html", 'title' => $key); + } + } + $templ->assign("packageindex",$this->package_index); + $templ->assign("subdir",''); + return $templ; + } + + /** + * Writes out the template file of {@link $class_data} and unsets the template to save memory + * @see registerCurrentClass() + * @see parent::endClass() + */ + function endClass() + { + $a = '../'; + if (!empty($this->subpackage)) $a .= '../'; + if ($this->juststarted) + { + $this->juststarted = false; + phpDocumentor_out("\n"); + flush(); + } + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->class_dir); + $this->class_data->assign("subdir",$a); + $this->class_data->register_outputfilter('HTMLframes_outputfilter'); + $this->writefile($this->class . '.html',$this->class_data->fetch('class.tpl')); + unset($this->class_data); + } + + /** + * Writes out the template file of {@link $page_data} and unsets the template to save memory + * @see registerCurrent() + * @see parent::endPage() + */ + function endPage() + { + $this->package = $this->curpage->package; + $this->subpackage = $this->curpage->subpackage; + $a = '../'; + if (!empty($this->subpackage)) $a .= '../'; + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->page_dir); + $this->page_data->assign("package",$this->package); + $this->page_data->assign("subdir",$a); + $this->page_data->register_outputfilter('HTMLframes_outputfilter'); + $this->writefile($this->page . '.html',$this->page_data->fetch('page.tpl')); + unset($this->page_data); + } + + /** + * @param string + * @param string + * @return string <a href="'.$link.'">'.$text.''.$text.''; + } + + function makeLeft() + { + foreach($this->page_elements as $package => $o1) + { + foreach($o1 as $subpackage => $links) + { + for($i=0;$i $this->getId($links[$i]), "title" => $links[$i]->name); + } + } + } + foreach($this->class_elements as $package => $o1) + { + foreach($o1 as $subpackage => $links) + { + for($i=0;$iclasses->getClassByPackage($links[$i]->name, $links[$i]->package); + if ($class && isset($class->docblock) && $class->docblock->hasaccess) + $left[$package][$subpackage]['classes'][] = + array("link" => $this->getId($links[$i]), + "title" => $links[$i]->name, + "access" => $class->docblock->tags['access'][0]->value, + "abstract" => isset ($class->docblock->tags['abstract'][0])); + else + $left[$package][$subpackage]['classes'][] = + array("link" => $this->getId($links[$i]), + "title" => $links[$i]->name, + "access" => 'public', + "abstract" => isset ($class->docblock->tags['abstract'][0])); + } + } + } + foreach($this->function_elements as $package => $o1) + { + foreach($o1 as $subpackage => $links) + { + for($i=0;$i $this->getId($links[$i]), "title" => $links[$i]->name); + } + } + } + $ret = array(); + foreach($left as $package => $r) + { + $pd = 'blank'; + if (isset($this->package_pages[$package])) $pd = $package.'/package_'.$package.'.html'; + if (!isset($r[''])) + { + $pt = false; + $ptnoa = false; + $ptt = $package; + if ($t = $this->hasTutorial('pkg',$package,$package,'')) + { + $pt = $t->getLink($this); + $ptnoa = $this->getId($t->getLink($this,true)); + $ptt = $t->getTitle($this); + } + $tutes = array(); + foreach($this->tutorial_tree as $root => $tr) + { + if ($tr['tutorial']->package == $package && $tr['tutorial']->subpackage == $subpackage) + $tutes[$tr['tutorial']->tutorial_type][] = $this->getTutorialTree($tr['tutorial']); + } + if (isset($this->childless_tutorials[$package][$subpackage])) + { + foreach($this->childless_tutorials[$package][$subpackage] as $ext => $other) + { + foreach($other as $tutorial) + { + $tutes[$tutorial->tutorial_type][] = $this->getTutorialTree($tutorial); + } + } + } + $ret[$package][] = + array( + 'package' => $package, + 'subpackage' => '', + 'packagedoc' => $pd, + 'packagetutorial' => $pt, + 'packagetutorialnoa' => $ptnoa, + 'packagetutorialtitle' => $ptt, + 'files' => array(), + 'functions' => array(), + 'classes' => array(), + 'tutorials' => $tutes, + ); + } + foreach($r as $subpackage => $info) + { + $my = array(); + $my['package'] = $package; + if (isset($this->package_pages[$package])) + $my['packagedoc'] = $pd; + else + $my['packagedoc'] = 'blank'; + $my['subpackage'] = $subpackage; + if (empty($subpackage)) + { + if ($t = $this->hasTutorial('pkg',$package,$package,$subpackage)) + { + $my['packagetutorial'] = $t->getLink($this); + $my['packagetutorialnoa'] = $this->getId($t->getLink($this,true)); + $my['packagetutorialtitle'] = $t->getTitle($this); + } else + { + $my['packagetutorial'] = 'No Package-Level Tutorial'; + $my['packagetutorialnoa'] = 'blank.html'; + $my['packagetutorialtitle'] = $package; + } + } else + { + if ($t = $this->hasTutorial('pkg',$subpackage,$package,$subpackage)) + { + $my['subpackagetutorial'] = $this->returnSee($this->getTutorialLink($t)); + $my['subpackagetutorialnoa'] = $this->getId($t->getLink($this,true)); + $my['subpackagetutorialtitle'] = $t->getTitle($this); + } else + { + $my['subpackagetutorial'] = false; + $my['subpackagetutorialnoa'] = false; + $my['subpackagetutorialtitle'] = $subpackage; + } + } + $tutes = array(); + foreach($this->tutorial_tree as $root => $tr) + { + if ($tr['tutorial']->package == $package && $tr['tutorial']->subpackage == $subpackage) + { + $tutes[$tr['tutorial']->tutorial_type][] = $this->getTutorialTree($tr['tutorial']); + } + } + $my['tutorials'] = $tutes; + $my['files'] = $my['classes'] = $my['functions'] = array(); + if (isset($info['files'])) + $my['files'] = $info['files']; + if (isset($info['classes'])) + $my['classes'] = $info['classes']; + if (isset($info['functions'])) + $my['functions'] = $info['functions']; + $ret[$package][] = $my; + } + } + return $ret; + } + + function getTutorialTree($tutorial,$k = false) + { + $ret = ''; + if (is_object($tutorial)) $tree = parent::getTutorialTree($tutorial); else $tree = $tutorial; +// debug($this->vardump_tree($tree));exit; + if (!$tree) + { + $template = &$this->newSmarty(); + $template->assign('subtree',false); + $template->assign('name',str_replace('.','',$tutorial->name)); + $template->assign('parent',false); + $template->assign('haskids',false); + $template->assign('kids',''); + $link = new tutorialLink; + $t = $tutorial; + $link->addLink('',$t->path,$t->name,$t->package,$t->subpackage,$t->getTitle($this)); + $main = array('link' => $this->getId($link), 'title' => $link->title); + $template->assign('main',$main); + return $template->fetch('tutorial_tree.tpl'); + } + if (isset($tree['kids'])) + { + foreach($tree['kids'] as $subtree) + { + $ret .= $this->getTutorialTree($subtree, true); + } + } + $template = &$this->newSmarty(); + $template->assign('subtree',$k); + $template->assign('name',str_replace('.','',$tree['tutorial']->name)); + $template->assign('parent',($k ? str_replace('.','',$tree['tutorial']->parent->name) : false)); + $template->assign('haskids',strlen($ret)); + $template->assign('kids',$ret); + $link = new tutorialLink; + $t = $tree['tutorial']; + $link->addLink('',$t->path,$t->name,$t->package,$t->subpackage,$t->getTitle($this)); + $main = array('link' => $this->getId($link), 'title' => $link->title); + $template->assign('main',$main); + $ret = $template->fetch('tutorial_tree.tpl'); + return $ret; + } + + /** + * HTMLdefaultConverter chooses to format both package indexes and the complete index here + * + * This function formats output for the elementindex.html and pkgelementindex.html template files. It then + * writes them to the target directory + * @see generateElementIndex(), generatePkgElementIndex() + */ + function formatPkgIndex() + { + list($package_indexes,$packages,$mletters) = $this->generatePkgElementIndexes(); + for($i=0;$inewSmarty(); + $this->package = $package_indexes[$i]['package']; + $this->subpackage = ''; + $template->assign("index",$package_indexes[$i]['pindex']); + $template->assign("package",$package_indexes[$i]['package']); + $template->assign("letters",$mletters[$package_indexes[$i]['package']]); + $template->register_outputfilter('HTMLframes_outputfilter'); + $this->setTargetDir($this->base_dir); + $this->writefile('elementindex_'.$package_indexes[$i]['package'].'.html',$template->fetch('pkgelementindex.tpl')); + } + phpDocumentor_out("\n"); + flush(); + } + + /** + * HTMLdefaultConverter uses this function to format template index.html and packages.html + * + * This function generates the package list from {@link $all_packages}, eliminating any + * packages that don't have any entries in their package index (no files at all, due to @ignore + * or other factors). Then it uses the default package name as the first package index to display. + * It sets the right pane to be either a blank file with instructions on making package-level docs, + * or the package-level docs for the default package. + * @global string Used to set the starting package to display + */ + function formatIndex() + { + global $phpDocumentor_DefaultPackageName; + list($elindex,$mletters) = $this->generateElementIndex(); + $template = &$this->newSmarty(); + $template->assign("index",$elindex); + $template->assign("letters",$mletters); + $template->register_outputfilter('HTMLframes_outputfilter'); + phpDocumentor_out("\n"); + flush(); + $this->setTargetDir($this->base_dir); + $this->writefile('elementindex.html',$template->fetch('elementindex.tpl')); + usort($this->package_index,"HTMLframes_pindexcmp"); + $index = &$this->newSmarty(); + foreach($this->all_packages as $key => $val) + { + if (isset($this->pkg_elements[$key])) + { + if (!isset($start)) $start = $key; + if (!isset($this->package_pages[$key])) $this->writeNewPPage($key); + } + } + // Created index.html + if (isset($this->pkg_elements[$phpDocumentor_DefaultPackageName])) $start = $phpDocumentor_DefaultPackageName; + $this->package = $start; + $this->subpackage = ''; + $index->assign("package_count",count($this->pkg_elements)); + if (count($this->ric_set)) + $index->assign("package_count",2); + $index->assign("date",date("r",time())); + $index->assign("title",$this->title); + $index->assign("start","li_$start.html"); + $index->register_outputfilter('HTMLframes_outputfilter'); + if (isset($this->tutorials[$start]['']['pkg'][$start . '.pkg'])) + { + $index->assign("blank",$start.'/tutorial_'.$start.'.pkg'); + } elseif (isset($this->package_pages[$start])) + { + $index->assign("blank",$start.'/package_'.$start); + } + else + { + $index->assign("blank","blank"); + $blank = &$this->newSmarty(); + $blank->assign('package',$phpDocumentor_DefaultPackageName); + $this->setTargetDir($this->base_dir); + $this->writefile("blank.html",$blank->fetch('blank.tpl')); + } + phpDocumentor_out("\n"); + flush(); + $this->setTargetDir($this->base_dir); + $this->writefile("index.html",$index->fetch('index.tpl')); + + // Create package index + $package = &$this->newSmarty(); + $package->assign('ric',array()); + if (isset($this->ric_set)) + { + foreach($this->ric_set as $name => $u) + { + $package->append('ric',array('file' => 'ric_'.$name.'.html','name' => $name)); + } + } + $package->assign("packages",$this->package_index); + $package->register_outputfilter('HTMLframes_outputfilter'); + $this->writefile("packages.html",$package->fetch('top_frame.tpl')); + unset($index); + } + + function writeNewPPage($key) + { + return; + $template = &$this->newSmarty(); + $this->package = $key; + $this->subpackage = ''; + $template->assign("date",date("r",time())); + $template->assign("title",$this->title); + $template->assign("package",$key); + $template->register_outputfilter('HTMLframes_outputfilter'); + phpDocumentor_out("\n"); + flush(); + $this->setTargetDir($this->base_dir); + + $this->writefile("li_$key.html",$template->fetch('index.tpl')); + unset($template); + } + + /** + * Generate indexes for li_package.html and classtree output files + * + * This function generates the li_package.html files from the template file left.html. It does this by + * iterating through each of the $page_elements, $class_elements and $function_elements arrays to retrieve + * the pre-sorted {@link abstractLink} descendants needed for index generation. Conversion of these links to + * text is done by {@link returnSee()}. The {@link $local} parameter is set to false to ensure that paths are correct. + * + * Then it uses {@link generateFormattedClassTrees()} to create class trees from the template file classtrees.html. Output + * filename is classtrees_packagename.html. This function also unsets {@link $elements} and {@link $pkg_elements} to free + * up the considerable memory these two class vars use + * @see $page_elements, $class_elements, $function_elements + */ + function formatLeftIndex() + { + phpDocumentor_out("\n"); + flush(); + $this->setTargetDir($this->base_dir); + if (0)//!isset($this->left)) + { + debug("Nothing parsed, check the command-line"); + die(); + } + $x = $this->makeLeft(); + foreach($this->all_packages as $package => $rest) + { + if (!isset($this->pkg_elements[$package])) continue; + $template = &$this->newSmarty(); + $template->assign("info",$x[$package]); + $template->assign('package',$package); + $template->assign("hastutorials",isset($this->tutorials[$package])); + $template->assign('hastodos',count($this->todoList)); + $template->assign('todolink','todolist.html'); + $template->assign("classtreepage","classtrees_$package"); + $template->assign("elementindex","elementindex_$package"); + $template->register_outputfilter('HTMLframes_outputfilter'); + if (isset($this->package_pages[$package])) + { + $template->assign("packagedoc",$package.'/package_' . $package . '.html'); + } else + { + $template->assign("packagedoc",false); + } + $this->writefile("li_$package.html",$template->fetch('left_frame.tpl')); + + // Create class tree page + $template = &$this->newSmarty(); + $template->assign("classtrees",$this->generateFormattedClassTrees($package)); + $template->assign("package",$package); + $template->register_outputfilter('HTMLframes_outputfilter'); + $this->writefile("classtrees_$package.html",$template->fetch('classtrees.tpl')); + phpDocumentor_out("\n"); + flush(); + } + // free up considerable memory + unset($this->elements); + unset($this->pkg_elements); + } + + /** + * This function takes an {@link abstractLink} descendant and returns an html link + * + * @param abstractLink a descendant of abstractlink should be passed, and never text + * @param string text to display in the link + * @param boolean this parameter is not used, and is deprecated + * @param boolean determines whether the returned text is enclosed in an tag + */ + function returnSee(&$element, $eltext = false, $with_a = true) + { + if (!is_object($element) || !$element) return false; + if (!$with_a) return $this->getId($element, false); + if (!$eltext) + { + $eltext = ''; + switch($element->type) + { + case 'tutorial' : + $eltext = strip_tags($element->title); + break; + case 'method' : + case 'var' : + case 'const' : + $eltext .= $element->class.'::'; + case 'page' : + case 'define' : + case 'class' : + case 'function' : + case 'global' : + default : + $eltext .= $element->name; + if ($element->type == 'function' || $element->type == 'method') $eltext .= '()'; + break; + } + } + return ''.$eltext.''; + } + + function getId($element, $fullpath = true) + { + if (phpDocumentor_get_class($element) == 'parserdata') + { + $element = $this->addLink($element->parent); + $elp = $element->parent; + } elseif (is_a($element, 'parserbase')) + { + $elp = $element; + $element = $this->addLink($element); + } + $c = ''; + if (!empty($element->subpackage)) + { + $c = '/'.$element->subpackage; + } + $b = '{$subdir}'; + switch ($element->type) + { + case 'page' : + if ($fullpath) + return $b.$element->package.$c.'/'.$element->fileAlias.'.html'; + return 'top'; + break; + case 'define' : + case 'global' : + case 'function' : + if ($fullpath) + return $b.$element->package.$c.'/'.$element->fileAlias.'.html#'.$element->type.$element->name; + return $element->type.$element->name; + break; + case 'class' : + if ($fullpath) + return $b.$element->package.$c.'/'.$element->name.'.html'; + return 'top'; + break; + case 'method' : + case 'var' : + case 'const' : + if ($fullpath) + return $b.$element->package.$c.'/'.$element->class.'.html#'.$element->type.$element->name; + return $element->type.$element->name; + break; + case 'tutorial' : + $d = ''; + if ($element->section) + { + $d = '#'.$element->section; + } + return $b.$element->package.$c.'/tutorial_'.$element->name.'.html'.$d; + } + } + + /** + * Convert README/INSTALL/CHANGELOG file contents to output format + * @param README|INSTALL|CHANGELOG + * @param string contents of the file + */ + function Convert_RIC($name, $contents) + { + $template = &$this->newSmarty(); + $template->assign('contents',$contents); + $template->assign('name',$name); + $this->setTargetDir($this->base_dir); + $this->writefile('ric_'.$name . '.html',$template->fetch('ric.tpl')); + $this->ric_set[$name] = true; + } + + function ConvertTodoList() + { + $todolist = array(); + foreach($this->todoList as $package => $alltodos) + { + foreach($alltodos as $todos) + { + $converted = array(); + $converted['link'] = $this->returnSee($todos[0]); + if (!is_array($todos[1])) + { + $converted['todos'][] = $todos[1]->Convert($this); + } else + { + foreach($todos[1] as $todo) + { + $converted['todos'][] = $todo->Convert($this); + } + } + $todolist[$package][] = $converted; + } + } + $templ = &$this->newSmarty(); + $templ->assign('todos',$todolist); + $templ->register_outputfilter('HTMLframes_outputfilter'); + $this->setTargetDir($this->base_dir); + $this->writefile('todolist.html',$templ->fetch('todolist.tpl')); + } + + /** + * Create errors.html template file output + * + * This method takes all parsing errors and warnings and spits them out ordered by file and line number. + * @global ErrorTracker We'll be using it's output facility + */ + function ConvertErrorLog() + { + global $phpDocumentor_errors; + $allfiles = array(); + $files = array(); + $warnings = $phpDocumentor_errors->returnWarnings(); + $errors = $phpDocumentor_errors->returnErrors(); + $template = &$this->newSmarty(); + foreach($warnings as $warning) + { + $file = '##none'; + $linenum = 'Warning'; + if ($warning->file) + { + $file = $warning->file; + $allfiles[$file] = 1; + $linenum .= ' on line '.$warning->linenum; + } + $files[$file]['warnings'][] = array('name' => $linenum, 'listing' => $warning->data); + } + foreach($errors as $error) + { + $file = '##none'; + $linenum = 'Error'; + if ($error->file) + { + $file = $error->file; + $allfiles[$file] = 1; + $linenum .= ' on line '.$error->linenum; + } + $files[$file]['errors'][] = array('name' => $linenum, 'listing' => $error->data); + } + $i=1; + $af = array(); + foreach($allfiles as $file => $num) + { + $af[$i++] = $file; + } + $allfiles = $af; + usort($allfiles,'strnatcasecmp'); + $allfiles[0] = "Post-parsing"; + foreach($allfiles as $i => $a) + { + $allfiles[$i] = array('file' => $a); + } + $out = array(); + foreach($files as $file => $data) + { + if ($file == '##none') $file = 'Post-parsing'; + $out[$file] = $data; + } + $template->assign("files",$allfiles); + $template->assign("all",$out); + $template->assign("title","phpDocumentor Parser Errors and Warnings"); + $this->setTargetDir($this->base_dir); + $this->writefile("errors.html",$template->fetch('errors.tpl')); + unset($template); + phpDocumentor_out("\n\nTo view errors and warnings, look at ".$this->base_dir. PATH_DELIMITER . "errors.html\n"); + flush(); + } + + function getTutorialId($package,$subpackage,$tutorial,$id) + { + return $id; + } + + function getCData($value) + { + return '
        '.htmlentities($value).'
        '; + } + + /** + * Converts package page and sets its package as used in {@link $package_pages} + * @param parserPackagePage + */ + function convertPackagepage(&$element) + { + phpDocumentor_out("\n"); + flush(); + $this->package = $element->package; + $this->subpackage = ''; + $contents = $element->Convert($this); + $this->package_pages[$element->package] = str_replace('{$subdir}','../',$contents); + phpDocumentor_out("\n"); + flush(); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $element->package); + $this->writeFile('package_'.$element->package.'.html',str_replace('{$subdir}','../',$contents)); + } + + /** + * @param parserTutorial + */ + function convertTutorial(&$element) + { + phpDocumentor_out("\n"); + flush(); + $template = &parent::convertTutorial($element); + $a = '../'; + if ($element->subpackage) $a .= '../'; + $template->assign('subdir',$a); + $template->register_outputfilter('HTMLframes_outputfilter'); + $contents = $template->fetch('tutorial.tpl'); + $a = ''; + if ($element->subpackage) $a = PATH_DELIMITER . $element->subpackage; + phpDocumentor_out("\n"); + flush(); + $this->setTargetDir($this->base_dir . PATH_DELIMITER . $element->package . $a); + $this->writeFile('tutorial_'.$element->name.'.html',$contents); + } + + /** + * Converts class for template output + * @see prepareDocBlock(), generateChildClassList(), generateFormattedClassTree(), getFormattedConflicts() + * @see getFormattedInheritedMethods(), getFormattedInheritedVars() + * @param parserClass + */ + function convertClass(&$element) + { + parent::convertClass($element); + $this->class_dir = $element->docblock->package; + if (!empty($element->docblock->subpackage)) $this->class_dir .= PATH_DELIMITER . $element->docblock->subpackage; + $a = '../'; + if ($element->docblock->subpackage != '') $a = "../$a"; + + $this->class_data->assign('subdir',$a); + $this->class_data->assign("title","Docs For Class " . $element->getName()); + $this->class_data->assign("page",$element->getName() . '.html'); + } + + /** + * Converts class variables for template output + * @see prepareDocBlock(), getFormattedConflicts() + * @param parserDefine + */ + function convertVar(&$element) + { + parent::convertVar($element, array('var_dest' => $this->getId($element,false))); + } + + /** + * Converts class variables for template output + * @see prepareDocBlock(), getFormattedConflicts() + * @param parserDefine + */ + function convertConst(&$element) + { + parent::convertConst($element, array('const_dest' => $this->getId($element,false))); + } + + /** + * Converts class methods for template output + * @see prepareDocBlock(), getFormattedConflicts() + * @param parserDefine + */ + function convertMethod(&$element) + { + parent::convertMethod($element, array('method_dest' => $this->getId($element,false))); + } + + /** + * Converts function for template output + * @see prepareDocBlock(), parserFunction::getFunctionCall(), getFormattedConflicts() + * @param parserFunction + */ + function convertFunction(&$element) + { + $funcloc = $this->getId($this->addLink($element)); + parent::convertFunction($element,array('function_dest' => $this->getId($element,false))); + } + + /** + * Converts include elements for template output + * @see prepareDocBlock() + * @param parserInclude + */ + function convertInclude(&$element) + { + parent::convertInclude($element, array('include_file' => '_'.strtr($element->getValue(),array('"' => '', "'" => '','.' => '_')))); + } + + /** + * Converts defines for template output + * @see prepareDocBlock(), getFormattedConflicts() + * @param parserDefine + */ + function convertDefine(&$element) + { + parent::convertDefine($element, array('define_link' => $this->getId($element,false))); + } + + /** + * Converts global variables for template output + * @param parserGlobal + */ + function convertGlobal(&$element) + { + parent::convertGlobal($element, array('global_link' => $this->getId($element,false))); + } + + /** + * converts procedural pages for template output + * @see prepareDocBlock(), getClassesOnPage() + * @param parserData + */ + function convertPage(&$element) + { + parent::convertPage($element); + $this->juststarted = true; + $this->page_dir = $element->parent->package; + if (!empty($element->parent->subpackage)) $this->page_dir .= PATH_DELIMITER . $element->parent->subpackage; + // registering stuff on the template + $this->page_data->assign("page",$this->getPageName($element) . '.html'); + $this->page_data->assign("title","Docs for page ".$element->parent->getFile()); + } + + function getPageName(&$element) + { + if (phpDocumentor_get_class($element) == 'parserpage') return '_'.$element->getName(); + return '_'.$element->parent->getName(); + } + + /** + * returns an array containing the class inheritance tree from the root object to the class + * + * @param parserClass class variable + * @return array Format: array(root,child,child,child,...,$class) + * @uses parserClass::getParentClassTree() + */ + + function generateFormattedClassTree($class) + { + $tree = $class->getParentClassTree($this); + $out = ''; + if (count($tree) - 1) + { + $result = array($class->getName()); + $parent = $tree[$class->getName()]; + $distance[] = ''; + while ($parent) + { + $x = $parent; + if (is_object($parent)) + { + $subpackage = $parent->docblock->subpackage; + $package = $parent->docblock->package; + $x = $parent; + $x = $parent->getLink($this); + if (!$x) $x = $parent->getName(); + } + $result[] = + $x; + $distance[] = + "\n%s|\n" . + "%s--"; + if (is_object($parent)) + $parent = $tree[$parent->getName()]; + elseif (isset($tree[$parent])) + $parent = $tree[$parent]; + } + $nbsp = ' '; + for($i=count($result) - 1;$i>=0;$i--) + { + $my_nbsp = ''; + for($j=0;$jarray_reverse($result),'distance'=>array_reverse($distance)); + } else + { + return array('classes'=>$class->getName(),'distance'=>array('')); + } + } + + /** @access private */ + function sortVar($a, $b) + { + return strnatcasecmp($a->getName(),$b->getName()); + } + + /** @access private */ + function sortMethod($a, $b) + { + if ($a->isConstructor) return -1; + if ($b->isConstructor) return 1; + return strnatcasecmp($a->getName(),$b->getName()); + } + + /** + * returns a template-enabled array of class trees + * + * @param string $package package to generate a class tree for + * @see $roots, HTMLConverter::getRootTree() + */ + function generateFormattedClassTrees($package) + { + if (!isset($this->roots[$package])) return array(); + $roots = $trees = array(); + $roots = $this->roots[$package]; + for($i=0;$i $roots[$i],'class_tree' => "
          \n".$this->getRootTree($this->getSortedClassTreeFromClass($roots[$i],$package,''),$package)."
        \n"); + } + return $trees; + } + + /** + * return formatted class tree for the Class Trees page + * + * @param array $tree output from {@link getSortedClassTreeFromClass()} + * @see Classes::$definitechild, generateFormattedClassTrees() + * @return string + */ + function getRootTree($tree,$package) + { + if (!$tree) return ''; + $my_tree = ''; + $cur = '#root'; + $lastcur = array(false); + $kids = array(); + $dopar = false; + if ($tree[$cur]['parent']) + { + $dopar = true; + if (!is_object($tree[$cur]['parent'])) + { +// debug("parent ".$tree[$cur]['parent']." not found"); + $my_tree .= '
      • ' . $tree[$cur]['parent'] .'
          '; + } + else + { +// debug("parent ".$this->returnSee($tree[$cur]['parent'])." in other package"); + $my_tree .= '
        • ' . $this->returnSee($tree[$cur]['parent']); + if ($tree[$cur]['parent']->package != $package) $my_tree .= ' (Different package)
            '; + } + } + do + { +// fancy_debug($cur,$lastcur,$kids); + if (count($tree[$cur]['children'])) + { +// debug("$cur has children"); + if (!isset($kids[$cur])) + { +// debug("set $cur kids"); + $kids[$cur] = 1; + $my_tree .= '
          • '.$this->returnSee($tree[$cur]['link']); + $my_tree .= '
              '."\n"; + } + array_push($lastcur,$cur); + list(,$cur) = each($tree[$cur]['children']); +// var_dump('listed',$cur); + if ($cur) + { + $cur = $cur['package'] . '#' . $cur['class']; +// debug("set cur to child $cur"); +// $my_tree .= '
            • '.$this->returnSee($tree[$cur]['link']); + continue; + } else + { +// debug("end of children for $cur"); + $cur = array_pop($lastcur); + $cur = array_pop($lastcur); + $my_tree .= '
          • '."\n"; + if ($dopar && ($cur == '#root' || !$cur)) $my_tree .= '
        • '; + } + } else + { +// debug("$cur has no children"); + $my_tree .= '
        • '.$this->returnSee($tree[$cur]['link'])."
        • "; + if ($dopar && $cur == '#root') $my_tree .= '
      • '; + $cur = array_pop($lastcur); + } + } while ($cur); + return $my_tree; + } + /** + * Generate indexing information for given element + * + * @param parserElement descendant of parserElement + * @see generateElementIndex() + * @return array + */ + function getIndexInformation($elt) + { + $Result['type'] = $elt->type; + $Result['file_name'] = $elt->file; + $Result['path'] = $elt->getPath(); + + if (isset($elt->docblock)) + { + $Result['description'] = $elt->docblock->getSDesc($this); + + if ($elt->docblock->hasaccess) + $Result['access'] = $elt->docblock->tags['access'][0]->value; + else + $Result['access'] = 'public'; + + $Result['abstract'] = isset ($elt->docblock->tags['abstract'][0]); + } + else + $Result['description'] = ''; + + $aa = $Result['description']; + if (!empty($aa)) $aa = "
            $aa"; + + switch($elt->type) + { + case 'class': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Class'; + $Result['link'] = $this->getClassLink($elt->getName(), + $elt->docblock->package, + $elt->getPath(), + $elt->getName()); + $Result['listing'] = 'in file '.$elt->file.', class '.$Result['link']."$aa"; + break; + case 'define': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Constant'; + $Result['link'] = $this->getDefineLink($elt->getName(), + $elt->docblock->package, + $elt->getPath(), + $elt->getName()); + $Result['listing'] = 'in file '.$elt->file.', constant '.$Result['link']."$aa"; + break; + case 'global': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Global'; + $Result['link'] = $this->getGlobalLink($elt->getName(), + $elt->docblock->package, + $elt->getPath(), + $elt->getName()); + $Result['listing'] = 'in file '.$elt->file.', global variable '.$Result['link']."$aa"; + break; + case 'function': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Function'; + $Result['link'] = $this->getFunctionLink($elt->getName(), + $elt->docblock->package, + $elt->getPath(), + $elt->getName().'()'); + $Result['listing'] = 'in file '.$elt->file.', function '.$Result['link']."$aa"; + break; + case 'method': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Method'; + $Result['link'] = $this->getMethodLink($elt->getName(), + $elt->class, + $elt->docblock->package, + $elt->getPath(), + $elt->class.'::'.$elt->getName().'()' + ); + if ($elt->isConstructor) $Result['constructor'] = 1; + $Result['listing'] = 'in file '.$elt->file.', method '.$Result['link']."$aa"; + break; + case 'var': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Variable'; + $Result['link'] = $this->getVarLink($elt->getName(), + $elt->class, + $elt->docblock->package, + $elt->getPath(), + $elt->class.'::'.$elt->getName()); + $Result['listing'] = 'in file '.$elt->file.', variable '.$Result['link']."$aa"; + break; + case 'const': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Class Constant'; + $Result['link'] = $this->getConstLink($elt->getName(), + $elt->class, + $elt->docblock->package, + $elt->getPath(), + $elt->class.'::'.$elt->getName()); + $Result['listing'] = 'in file '.$elt->file.', class constant '.$Result['link']."$aa"; + break; + case 'page': + $Result['name'] = $elt->getFile(); + $Result['title'] = 'Page'; + $Result['link'] = $this->getPageLink($elt->getFile(), + $elt->package, + $elt->getPath(), + $elt->getFile()); + $Result['listing'] = 'procedural page '.$Result['link']; + break; + case 'include': + $Result['name'] = $elt->getName(); + $Result['title'] = 'Include'; + $Result['link'] = $elt->getValue(); + $Result['listing'] = 'include '.$Result['name']; + break; + } + + return $Result; + } + /** + * Generate alphabetical index of all elements + * + * @see $elements, walk() + */ + function generateElementIndex() + { + $elementindex = array(); + $letters = array(); + $used = array(); + foreach($this->elements as $letter => $nutoh) + { + foreach($this->elements[$letter] as $i => $yuh) + { + if ($this->elements[$letter][$i]->type != 'include') + { + if (!isset($used[$letter])) + { + $letters[]['letter'] = $letter; + $elindex['letter'] = $letter; + $used[$letter] = 1; + } + + $elindex['index'][] = $this->getIndexInformation($this->elements[$letter][$i]); + } + } + if (isset($elindex['index'])) + { + $elementindex[] = $elindex; + } else + { + unset($letters[count($letters) - 1]); + } + $elindex = array(); + } + return array($elementindex,$letters); + } + + function copyMediaRecursively($media,$targetdir,$subdir = '') + { + if (!is_array($media)) { + return; + } + foreach($media as $dir => $files) + { + if ($dir === '/') + { + $this->copyMediaRecursively($files,$targetdir); + } else + { + if (!is_numeric($dir)) + { + // create the subdir + phpDocumentor_out("creating $targetdir/$dir\n"); + Converter::setTargetDir($targetdir . PATH_DELIMITER . $dir); + if (!empty($subdir)) $subdir .= PATH_DELIMITER; + $this->copyMediaRecursively($files,"$targetdir/$dir",$subdir . $dir); + } else + { + // copy the file + phpDocumentor_out("copying $targetdir/".$files['file']."\n"); + $this->copyFile($files['file'],$subdir); + } + } + } + } + + /** + * calls the converter setTargetDir, and then copies any template images and the stylesheet if they haven't been copied + * @see Converter::setTargetDir() + */ + function setTargetDir($dir) + { + Converter::setTargetDir($dir); + if ($this->wrote) return; + $this->wrote = true; + $template_images = array(); + $stylesheets = array(); + $tdir = $dir; + $dir = $this->templateDir; + $this->templateDir = $this->templateDir.'templates/'; + $info = new Io; + $this->copyMediaRecursively($info->getDirTree($this->templateDir.'media',$this->templateDir),$tdir); + } + + /** + * Generate alphabetical index of all elements by package and subpackage + * + * @param string $package name of a package + * @see $pkg_elements, walk(), generatePkgElementIndexes() + */ + function generatePkgElementIndex($package) + { +// var_dump($this->pkg_elements[$package]); + $elementindex = array(); + $letters = array(); + $letterind = array(); + $used = array(); + $subp = ''; + foreach($this->pkg_elements[$package] as $subpackage => $els) + { + if (empty($els)) continue; + if (!empty($subpackage)) $subp = " (subpackage: $subpackage)"; else $subp = ''; + foreach($els as $letter => $yuh) + { + foreach($els[$letter] as $i => $yuh) + { + if ($els[$letter][$i]->type != 'include') + { + if (!isset($used[$letter])) + { + $letters[]['letter'] = $letter; + $letterind[$letter] = count($letters) - 1; + $used[$letter] = 1; + } + $elindex[$letter]['letter'] = $letter; + + $elindex[$letter]['index'][] = $this->getIndexInformation($els[$letter][$i]); + } + } + } + } + ksort($elindex); + usort($letters,'HTMLframes_lettersort'); + if (isset($elindex)) + { + while(list($letter,$tempel) = each($elindex)) + { + if (!isset($tempel)) + { + unset($letters[$letterind[$tempel['letter']]]); + } else + $elementindex[] = $tempel; + } + } else $letters = array(); + return array($elementindex,$letters); + } + + /** + * + * @see generatePkgElementIndex() + */ + function generatePkgElementIndexes() + { + $packages = array(); + $package_names = array(); + $pkg = array(); + $letters = array(); + foreach($this->pkg_elements as $package => $trash) + { + $pkgs['package'] = $package; + $pkg['package'] = $package; + list($pkg['pindex'],$letters[$package]) = $this->generatePkgElementIndex($package); + if (count($pkg['pindex'])) + { + $packages[] = $pkg; + $package_names[] = $pkgs; + } + unset($pkgs); + unset($pkg); + } + foreach($packages as $i => $package) + { + $pnames = array(); + for($j=0;$jreturnSee($a, $text, $with_a); + } + + /** + * @param string name of function + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the function's documentation + * @see parent::getFunctionLink() + */ + function getFunctionLink($expr,$package, $file = false,$text = false) + { + $a = Converter::getFunctionLink($expr,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of define + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the define's documentation + * @see parent::getDefineLink() + */ + function getDefineLink($expr,$package, $file = false,$text = false) + { + $a = Converter::getDefineLink($expr,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of global variable + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the global variable's documentation + * @see parent::getGlobalLink() + */ + function getGlobalLink($expr,$package, $file = false,$text = false) + { + $a = Converter::getGlobalLink($expr,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of procedural page + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the procedural page's documentation + * @see parent::getPageLink() + */ + function getPageLink($expr,$package, $path = false,$text = false) + { + $a = Converter::getPageLink($expr,$package,$path); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of method + * @param string class containing method + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the method's documentation + * @see parent::getMethodLink() + */ + function getMethodLink($expr,$class,$package, $file = false,$text = false) + { + $a = Converter::getMethodLink($expr,$class,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of var + * @param string class containing var + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the var's documentation + * @see parent::getVarLink() + */ + function getVarLink($expr,$class,$package, $file = false,$text = false) + { + $a = Converter::getVarLink($expr,$class,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * @param string name of class constant + * @param string class containing class constant + * @param string package name + * @param string full path to look in (used in index generation) + * @param boolean deprecated + * @param boolean return just the URL, or enclose it in an html a tag + * @return mixed false if not found, or an html a link to the var's documentation + * @see parent::getVarLink() + */ + function getConstLink($expr,$class,$package, $file = false,$text = false) + { + $a = Converter::getConstLink($expr,$class,$package,$file); + if (!$a) return false; + return $this->returnSee($a, $text); + } + + /** + * does a nat case sort on the specified second level value of the array + * + * @param mixed $a + * @param mixed $b + * @return int + */ + function rcNatCmp ($a, $b) + { + $aa = strtoupper($a[$this->rcnatcmpkey]); + $bb = strtoupper($b[$this->rcnatcmpkey]); + + return strnatcasecmp($aa, $bb); + } + + /** + * does a nat case sort on the specified second level value of the array. + * this one puts constructors first + * + * @param mixed $a + * @param mixed $b + * @return int + */ + function rcNatCmp1 ($a, $b) + { + $aa = strtoupper($a[$this->rcnatcmpkey]); + $bb = strtoupper($b[$this->rcnatcmpkey]); + + if (strpos($aa,'CONSTRUCTOR') === 0) + { + return -1; + } + if (strpos($bb,'CONSTRUCTOR') === 0) + { + return 1; + } + if (strpos($aa,strtoupper($this->class)) === 0) + { + return -1; + } + if (strpos($bb,strtoupper($this->class)) === 0) + { + return -1; + } + return strnatcasecmp($aa, $bb); + } + + /** + * This function is not used by HTMLdefaultConverter, but is required by Converter + */ + function Output() + { + } +} + +/** + * @access private + * @global string name of the package to set as the first package + */ +function HTMLframes_pindexcmp($a, $b) +{ + global $phpDocumentor_DefaultPackageName; + if ($a['title'] == $phpDocumentor_DefaultPackageName) return -1; + if ($b['title'] == $phpDocumentor_DefaultPackageName) return 1; + return strnatcasecmp($a['title'],$b['title']); +} + +/** @access private */ +function HTMLframes_lettersort($a, $b) +{ + return strnatcasecmp($a['letter'],$b['letter']); +} + +/** @access private */ +function HTMLframes_outputfilter($src, &$smarty) +{ + return str_replace('{$subdir}',$smarty->_tpl_vars['subdir'],$src); +} +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/options.ini b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/options.ini new file mode 100644 index 00000000..73164a39 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/options.ini @@ -0,0 +1,577 @@ +preservedocbooktags = false + +;; used to highlight the {@source} inline tag, @filesource tag, and @example tag +[highlightSourceTokens] +;; format: +;; T_CONSTANTNAME = open +;; /T_CONSTANTNAME = close + +T_INCLUDE = +/T_INCLUDE = +T_INCLUDE_ONCE = +/T_INCLUDE_ONCE = +T_REQUIRE_ONCE = +/T_REQUIRE_ONCE = +T_REQUIRE_ONCE = +/T_REQUIRE_ONCE = + +T_CONSTANT_ENCAPSED_STRING = +/T_CONSTANT_ENCAPSED_STRING = +T_STRING_VARNAME = +/T_STRING_VARNAME = + +T_STRING = +/T_STRING = + +T_DNUMBER = +/T_DNUMBER = +T_LNUMBER = +/T_LNUMBER = + +T_VARIABLE = +/T_VARIABLE = + +T_COMMENT = +/T_COMMENT = +T_ML_COMMENT = +/T_ML_COMMENT = + +T_OBJECT_OPERATOR = +/T_OBJECT_OPERATOR = + +T_ABSTRACT = +/T_ABSTRACT = +T_CLONE = +/T_CLONE = +T_HALT_COMPILER = +/T_HALT_COMPILER = +T_ARRAY = +/T_ARRAY = +T_AS = +/T_AS = +T_BREAK = +/T_BREAK = +T_CLASS = +/T_CLASS = +T_CASE = +/T_CASE = +T_CONST = +/T_CONST = +T_CONTINUE = +/T_CONTINUE = +T_DECLARE = +/T_DECLARE = +T_DEFAULT = +/T_DEFAULT = +T_ELSE = +/T_ELSE = +T_ELSEIF = +/T_ELSEIF = +T_EMPTY = +/T_EMPTY = +T_ENDDECLARE = +/T_ENDDECLARE = +T_ENDFOR = +/T_ENDFOR = +T_ENDSWITCH = +/T_ENDSWITCH = +T_ENDFOREACH = +/T_ENDFOREACH = +T_ENDIF = +/T_ENDIF = +T_ENDWHILE = +/T_ENDWHILE = +T_EXIT = +/T_EXIT = +T_EXTENDS = +/T_EXTENDS = +T_FINAL = +/T_FINAL = +T_FOR = +/T_FOR = +T_FOREACH = +/T_FOREACH = +T_FUNCTION = +/T_FUNCTION = +T_GLOBAL = +/T_GLOBAL = +T_IF = +/T_IF = +T_IMPLEMENTS = +/T_IMPLEMENTS = +T_INTERFACE = +/T_INTERFACE = +T_LOGICAL_AND = +/T_LOGICAL_AND = +T_LOGICAL_OR = +/T_LOGICAL_OR = +T_LOGICAL_XOR = +/T_LOGICAL_XOR = +T_NEW = +/T_NEW = +T_PRIVATE = +/T_PRIVATE = +T_PROTECTED = +/T_PROTECTED = +T_PUBLIC = +/T_PUBLIC = +T_RETURN = +/T_RETURN = +T_STATIC = +/T_STATIC = +T_SWITCH = +/T_SWITCH = +T_VAR = +/T_VAR = +T_WHILE = +/T_WHILE = + +T_DOUBLE_COLON = +/T_DOUBLE_COLON = + +T_OPEN_TAG = +/T_OPEN_TAG = +T_OPEN_TAG_WITH_ECHO = +/T_OPEN_TAG_WITH_ECHO = +T_CLOSE_TAG = +/T_CLOSE_TAG = + + +[highlightSource] +;; this is for highlighting things that aren't tokens like "&" +;; format: +;; word = open +;; /word = close +@ = +/@ = +& = +/& = +[ = +/[ = +] = +/] = +! = +/! = +";" = +/; = +( = +/( = +) = +/) = +, = +/, = +{ = +/{ = +} = +/} = +""" = +/" = + +[highlightDocBlockSourceTokens] +;; this is for docblock tokens, using by phpDocumentor_HighlightParser +;; tagphptype is for "string" in @param string description, for example +docblock = +/docblock = +tagphptype = +/tagphptype = +tagvarname = +/tagvarname = +coretag = +/coretag = +tag = +/tag = +inlinetag = +/inlinetag = +internal = +/internal = +closetemplate = +/closetemplate = +docblocktemplate = +/docblocktemplate = + +[highlightTutorialSourceTokens] +;; this is for XML DocBook-based tutorials, highlighted by phpDocumentor_TutorialHighlightParser +;; +opentag = +/opentag = +;; +closetag = +/closetag = +;; +attribute = +/attribute = +;; +attributevalue = +/attributevalue = +;; &entity; +entity = +/entity = +;; +comment = +/comment = +;; {@inline tag} +itag = +/itag = + +;; used for translation of html in DocBlocks +[desctranslate] +ul =
          +/ul =
        +ol =
          +/ol =
        +li =
      • +/li =
      • +code =
        +/code = 
        +var = +/var = +samp = +/samp = +kbd = +/kbd = +pre =
        +/pre = 
        +p =

        +/p =

        +b = +/b = +i = +/i = +br =
        + +[ppage] +;; this is the DocBook package page translation section. All DocBook tags +;; that have a corresponding html tag must be listed here. Entities should +;; also be listed here +;; +;; examples: +;; 1) +;; tagname = newtagname +;; +;; This is the simplest case, where all attributes will be added into the +;; starting tag and the ending tag will be html/xml style +;; becomes and +;; becomes +;; +;; +;; 2) +;; tagname = newtagname +;; tagname->attr = newattrname +;; +;; in this case, everything will be like the first case, except tags like: +;; will become +;; +;; +;; 3) +;; tagname = newtagname +;; tagname->attr = newattrname +;; tagname->attr+value = newvalue +;; +;; in this case, the value is also translated to another. This can be useful +;; for instances such as focus="middle" changing to align="center" or something +;; of that nature. +;; will become +;; +;; +;; 4) +;; tagname = newtagname +;; tagname->attr1 = newattrname +;; tagname->attr2 = newattrname +;; tagname->attr1+value|attr2+value = newvalue +;; +;; in this case, two attributes combine to make one new attribute, and the combined +;; value is translated into a new value +;; will become +;; +;; +;; 5) +;; tagname = newtagname +;; tagname!attr = dummy +;; +;; here, the attribute will be ignored. dummy is not used and may be any value +;; will become +;; +;; +;; 6) +;; tagname = newtagname +;; tagname! = dummy +;; +;; here, all attributes will be ignored. dummy is not used and may be any value +;; will become +;; +;; +;; 7) +;; tagname = newtagname +;; tagname/ = 1 +;; +;; here, the tag will be translated as a single tag with no closing tag, and all +;; attributes +;; {text text} will become +;; +;; +;; 8) +;; tagname = +;; /tagname = closetagtext +;; +;; in this case, the text will be inserted exactly as entered for +;; and closetagtext for +;; will become +;; closetagtext +;; +;; 9) +;; $attr$my_attribute = newattrname +;; +;; tagname = newtagname +;; +;; in this case, all occurences of my_attribute in any tag will be changed to +;; newattrname. This is useful for changing things like role="php" to +;; class="php," for example. Note that the text "$attr$" MUST be on the line +;; start for phpDocumentor to recognize it. +;; +;; 10) +;; &entity; = translation text +;; " = " +;; " = """ +;; < = < +;; +;; Use this to control translation of entities to their appropriate values + +  =   +" = " +” = ” +“ = “ +& = & +< = < +> = > +© = © + + +$attr$role = class + +abbrev = abbr + +blockquote = blockquote + +arg = span +arg->choice = class + +author = +/author = +author! = 0 + +authorblurb =
        +/authorblurb =
        + +authorgroup =

        Authors

        +/authorgroup =
        +authorgroup! = 0 + +caution = +/caution = +caution! = 0 + +cmdsynopsis =
        +/cmdsynopsis =
        + +command = +/command = + +copyright =
        +/copyright =
        + +emphasis = em + +example =
        +/example = 
        +example! = 0 + +function = +/function = () + +formalpara = p + +graphic = img +graphic->fileref = src +graphic/ = + +important = strong + +informalequation = blockquote + +informalexample = div + +inlineequation = em + +itemizedlist = ul + +listitem = li + +literal = code + +literallayout = span + +option = " " +/option = + +orderedlist = ol + +para = p + +programlisting =
        +/programlisting = 
        +programlisting! = 0 + +refentry = div + +refnamediv =
        +/refnamediv =
        +refnamediv! = 0 + +refname =

        +/refname =

        + +refpurpose =

        +/refpurpose =

        + +refsynopsisdiv =
        +/refsynopsisdiv =
        +refsynopsisdiv! = 0 + +refsect1 = span + +refsect2 = span + +refsect3 = +/refsect3 =
        + +releaseinfo =
        ( +/releaseinfo = )
        + +simpara = +/simpara =
        +simpara! = 0 + +subscript = sub + +superscript = super + +table = table + +table->colsep = rules +table->rowsep = rules +table->colsep+1|rowsep+1 =all +table->colsep+1|rowsep+0 =cols +table->colsep+0|rowsep+1 =rows + +table->frame =frame +table->frame+all =border +table->frame+none =void +table->frame+sides =vsides +table->frame+top =above +table->frame+topbot =hsides + +thead = thead + +tfoot = tfoot + +tbody = tbody + +colspec = col + +tgroup = colgroup +tgroup/ = 1 +tgroup->cols = span + +row = tr + +entry = td +entry->morerows = colspan +entry->morerows+1 =2 +entry->morerows+2 =3 +entry->morerows+3 =4 +entry->morerows+4 =5 +entry->morerows+5 =6 +entry->morerows+6 =7 +entry->morerows+7 =8 +entry->morerows+8 =9 +entry->morerows+9 =10 +entry->morerows+10 =11 +;; add more if you need more colspans + +warning = +/warning = +warning! = 0 + +;; now begins the attributes that should be tags in cdata +[$attr$id] +open = a +;close = /a +cdata! = true +quotevalues = true +separator = "=" +;separateall = true +$id = name + +;; now begins the sections that deal with +[refsynopsisdiv_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <h1 class="title"> +close = </h1> + +[refsect1_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <h2 class="title"> +close = </h2> + +[refsect2_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <h3 class="title"> +close = </h3> + +[refsect3_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <h4 class="title"> +close = </h4> + +[para_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <div class="title"> +close = </div> + +[formalpara_title] +;tag_attr = true +;attr_name = title +cdata_start = true +;cdata_end = true +open = <div class="title"> +close = </div> + +[example_title] +;tag_attr = true +;attr_name = title +;cdata_start = true +cdata_end = true +open = </td></tr><tr><td><strong> +close = </strong> + +[table_title] +;tag_attr = true +;attr_name = true +cdata_start = true +open = <caption> +close = </caption> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/basicindex.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/basicindex.tpl new file mode 100644 index 00000000..711e1d2e --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/basicindex.tpl @@ -0,0 +1,47 @@ +<div class="index-letter-menu"> +{section name=letter loop=$letters} + <a class="index-letter" href="{$indexname}.html#{$letters[letter].letter}">{$letters[letter].letter}</a> +{/section} +</div> + +{section name=index loop=$index} + <a name="{$index[index].letter}"></a> + <div class="index-letter-section"> + <div style="float: left" class="index-letter-title">{$index[index].letter}</div> + <div style="float: right"><a href="#top">top</a></div> + <div style="clear: both"></div> + </div> + <dl> + {section name=contents loop=$index[index].index} + <dt class="field"> + {if ($index[index].index[contents].title == "Variable")} + <span class="var-title">{$index[index].index[contents].name}</span> + {elseif ($index[index].index[contents].title == "Global")} + <span class="var-title">{$index[index].index[contents].name}</span> + {elseif ($index[index].index[contents].title == "Method")} + <span class="method-title">{$index[index].index[contents].name}</span> + {elseif ($index[index].index[contents].title == "Function")} + <span class="method-title">{$index[index].index[contents].name}</span> + {elseif ($index[index].index[contents].title == "Constant")} + <span class="const-title">{$index[index].index[contents].name}</span> + {elseif ($index[index].index[contents].title == "Page") || ($index[index].index[contents].title == "Include")} + <span class="include-title">{$index[index].index[contents].name}</span> + {else} + {$index[index].index[contents].name} + {/if} + </dt> + <dd class="index-item-body"> + <div class="index-item-details">{$index[index].index[contents].link} in {$index[index].index[contents].file_name}</div> + {if $index[index].index[contents].description} + <div class="index-item-description">{$index[index].index[contents].description}</div> + {/if} + </dd> + {/section} + </dl> +{/section} + +<div class="index-letter-menu"> +{section name=letter loop=$letters} + <a class="index-letter" href="{$indexname}.html#{$letters[letter].letter}">{$letters[letter].letter}</a> +{/section} +</div> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/blank.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/blank.tpl new file mode 100644 index 00000000..1fbaca2f --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/blank.tpl @@ -0,0 +1,13 @@ +<html> +<head> + <title>{$maintitle} + + + + +

        {$maintitle}

        +Welcome to {$package}!
        +
        +This documentation was generated by phpDocumentor v{$phpdocversion}
        + + \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/class.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/class.tpl new file mode 100644 index 00000000..cc1c080b --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/class.tpl @@ -0,0 +1,402 @@ +{include file="header.tpl" top3=true} + +

        {if $is_interface}Interface{else}Class{/if} {$class_name}

        + + +
        +
        Description
        + +
        + {if $implements} +

        + Implements interfaces: +

          + {foreach item="int" from=$implements}
        • {$int}
        • {/foreach} +
        +

        + {/if} + {include file="docblock.tpl" type="class" sdesc=$sdesc desc=$desc} +

        + Located in {$source_location} (line {if $class_slink}{$class_slink}{else}{$line_number}{/if}) +

        + + {if $tutorial} +
        +
        Tutorial: {$tutorial}
        + {/if} + +
        {section name=tree loop=$class_tree.classes}{$class_tree.classes[tree]}{$class_tree.distance[tree]}{/section}
        + + {if $conflicts.conflict_type} +
        +
        Conflicts with classes:
        + {section name=me loop=$conflicts.conflicts} + {$conflicts.conflicts[me]}
        + {/section} +
        + {/if} +
        +
        + +{if $children} + +
        +
        Direct descendents
        + +
        + + + + + + {section name=kids loop=$children} + + + + + {/section} +
        ClassDescription
        {$children[kids].link} + {if $children[kids].sdesc} + {$children[kids].sdesc} + {else} + {$children[kids].desc} + {/if} +
        +
        +
        +{/if} + +{if $consts} + +
        +
        Class Constant Summary
        + +
        +
        + {section name=consts loop=$consts} +
        +  + {$consts[consts].const_name} = {$consts[consts].const_value} + +
        + {/section} +
        +
        +
        +{/if} + +{if $vars} + +
        +
        Variable Summary
        + +
        +
        + {section name=vars loop=$vars} +
        + {$vars[vars].var_type} + {$vars[vars].var_name} +
        + {/section} +
        +
        +
        +{/if} + +{if $methods} + +
        +
        Method Summary
        + +
        +
        + {section name=methods loop=$methods} +
        + {if $methods[methods].function_return} + {$methods[methods].function_return} + {/if} + {if $methods[methods].ifunction_call.returnsref}&{/if}{$methods[methods].function_name} + {if count($methods[methods].ifunction_call.params)} + ({section name=params loop=$methods[methods].ifunction_call.params}{if $smarty.section.params.iteration != 1}, {/if}{if $methods[methods].ifunction_call.params[params].default}[{/if}{$methods[methods].ifunction_call.params[params].type} {$methods[methods].ifunction_call.params[params].name}{if $methods[methods].ifunction_call.params[params].default} = {$methods[methods].ifunction_call.params[params].default}]{/if}{/section}) + {else} + () + {/if} +
        + {/section} +
        +
        +
        +{/if} + +{if $vars || $ivars} + +
        +
        Variables
        + +
        + {include file="var.tpl"} + {if $ivars} +

        Inherited Variables

        + + {section name=ivars loop=$ivars} +

        Inherited from {$ivars[ivars].parent_class}

        +
        + {section name=ivars2 loop=$ivars[ivars].ivars} + + {$ivars[ivars].ivars[ivars2].link}{if $ivars[ivars].ivars[ivars2].ivar_sdesc}: {$ivars[ivars].ivars[ivars2].ivar_sdesc}{/if}
        +
        + {/section} +
        + {/section} + {/if} +
        +
        +{/if} + +{if $methods || $imethods} + +
        +
        Methods
        + +
        + {include file="method.tpl"} + {if $imethods} +

        Inherited Methods

        + + {section name=imethods loop=$imethods} + +

        Inherited From {$imethods[imethods].parent_class}

        +
        + {section name=im2 loop=$imethods[imethods].imethods} + {$imethods[imethods].imethods[im2].link}{if $imethods[imethods].imethods[im2].ifunction_sdesc}: {$imethods[imethods].imethods[im2].ifunction_sdesc}{/if}
        + {/section} +
        + {/section} + {/if} +
        +
        +{/if} + +{if $consts || $iconsts} + +
        +
        Class Constants
        + +
        + {include file="const.tpl"} + {if $iconsts} +

        Inherited Constants

        + + {section name=iconsts loop=$iconsts} +

        Inherited from {$iconsts[iconsts].parent_class}

        +
        + {section name=iconsts2 loop=$iconsts[iconsts].iconsts} + + + {$iconsts[iconsts].iconsts[iconsts2].link}{if $iconsts[iconsts].iconsts[iconsts2].iconst_sdesc}: {$iconsts[iconsts].iconsts[iconsts2].iconst_sdesc}{/if}
        +
        + {/section} +
        + {/section} + {/if} +
        +
        +{/if} + +{include file="footer.tpl" top3=true} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/classtrees.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/classtrees.tpl new file mode 100644 index 00000000..5188e8cf --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/classtrees.tpl @@ -0,0 +1,11 @@ +{include file="header.tpl" top1=true} + + +

        + {$smarty.capture.title} +

        +{section name=classtrees loop=$classtrees} +

        Root class {$classtrees[classtrees].class}

        +{$classtrees[classtrees].class_tree} +{/section} +{include file="footer.tpl"} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/const.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/const.tpl new file mode 100644 index 00000000..4157488f --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/const.tpl @@ -0,0 +1,18 @@ +{section name=consts loop=$consts} + +
        + +
        + + + {$consts[consts].const_name} + = {$consts[consts].const_value|replace:"\n":"
        "}
        + (line {if $consts[consts].slink}{$consts[consts].slink}{else}{$consts[consts].line_number}{/if}) +
        +
        + + {include file="docblock.tpl" sdesc=$consts[consts].sdesc desc=$consts[consts].desc tags=$consts[consts].tags} + +
        +{/section} + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/define.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/define.tpl new file mode 100644 index 00000000..ab76faa2 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/define.tpl @@ -0,0 +1,24 @@ +{section name=def loop=$defines} + +
        + +
        + + {$defines[def].define_name} = {$defines[def].define_value|replace:"\n":"
        "} + (line {if $defines[def].slink}{$defines[def].slink}{else}{$defines[def].line_number}{/if}) +
        +
        + + {include file="docblock.tpl" sdesc=$defines[def].sdesc desc=$defines[def].desc tags=$defines[def].tags} + + {if $globals[glob].global_conflicts.conflict_type} +
        +
        Conflicts with constants:
        + {section name=me loop=$defines[def].define_conflicts.conflicts} + {$defines[def].define_conflicts.conflicts[me]}
        + {/section} +
        + {/if} + +
        +{/section} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/docblock.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/docblock.tpl new file mode 100644 index 00000000..8a87c9b7 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/docblock.tpl @@ -0,0 +1,14 @@ + +{if $sdesc} +

        {$sdesc}

        +{/if} +{if $desc} +

        {$desc}

        +{/if} +{if $tags} +
          + {section name=tags loop=$tags} +
        • {$tags[tags].keyword}: {$tags[tags].data}
        • + {/section} +
        +{/if} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/elementindex.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/elementindex.tpl new file mode 100644 index 00000000..6e651db1 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/elementindex.tpl @@ -0,0 +1,12 @@ +{include file="header.tpl" noleftindex=true} + +

        Full index

        +

        Package indexes

        + +
        +{include file="basicindex.tpl" indexname="elementindex"} +{include file="footer.tpl"} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/errors.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/errors.tpl new file mode 100644 index 00000000..1576a822 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/errors.tpl @@ -0,0 +1,21 @@ +{include file="header.tpl" noleftindex=true} +{section name=files loop=$files} +{$files[files].file}
        +{/section} +{foreach key=file item=issues from=$all} + +

        {$file}

        +{if count($issues.warnings)} +

        Warnings:


        +{section name=warnings loop=$issues.warnings} +{$issues.warnings[warnings].name} - {$issues.warnings[warnings].listing}
        +{/section} +{/if} +{if count($issues.errors)} +

        Errors:


        +{section name=errors loop=$issues.errors} +{$issues.errors[errors].name} - {$issues.errors[errors].listing}
        +{/section} +{/if} +{/foreach} +{include file="footer.tpl"} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/examplesource.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/examplesource.tpl new file mode 100644 index 00000000..c813280b --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/examplesource.tpl @@ -0,0 +1,6 @@ +{include file="header.tpl" title=$title} +

        {$title}

        +
        +{$source} +
        +{include file="footer.tpl"} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/filesource.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/filesource.tpl new file mode 100644 index 00000000..4fd821a2 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/filesource.tpl @@ -0,0 +1,8 @@ +{capture name="tutle"}File Source for {$name}{/capture} +{include file="header.tpl" title=$smarty.capture.tutle} +

        Source for file {$name}

        +

        Documentation is available at {$docs}

        +
        +{$source} +
        +{include file="footer.tpl"} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/footer.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/footer.tpl new file mode 100644 index 00000000..424ebbe2 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/footer.tpl @@ -0,0 +1,8 @@ +{if !$index} +

        + Documentation generated on {$date} by phpDocumentor {$phpdocversion} +

        +{/if} + {if $top3}{/if} + + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/function.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/function.tpl new file mode 100644 index 00000000..2750a97e --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/function.tpl @@ -0,0 +1,44 @@ +{section name=func loop=$functions} + +
        + +
        + {$functions[func].function_name} (line {if $functions[func].slink}{$functions[func].slink}{else}{$functions[func].line_number}{/if}) +
        + + {include file="docblock.tpl" sdesc=$functions[func].sdesc desc=$functions[func].desc tags=$functions[func].tags params=$functions[func].params function=false} + +
        + {$functions[func].function_return} + + {if $functions[func].ifunction_call.returnsref}&{/if}{$functions[func].function_name} + + {if count($functions[func].ifunction_call.params)} + ({section name=params loop=$functions[func].ifunction_call.params}{if $smarty.section.params.iteration != 1}, {/if}{if $functions[func].ifunction_call.params[params].hasdefault}[{/if}{$functions[func].ifunction_call.params[params].type} {$functions[func].ifunction_call.params[params].name}{if $functions[func].ifunction_call.params[params].hasdefault} = {$functions[func].ifunction_call.params[params].default|escape:"html"}]{/if}{/section}) + {else} + () + {/if} +
        + + {if $functions[func].params} +
          + {section name=params loop=$functions[func].params} +
        • + {$functions[func].params[params].datatype} + {$functions[func].params[params].var}{if $functions[func].params[params].data}: {$functions[func].params[params].data}{/if} +
        • + {/section} +
        + {/if} + + {if $functions[func].function_conflicts.conflict_type} +
        +
        Conflicts with functions:
        + {section name=me loop=$functions[func].function_conflicts.conflicts} + {$functions[func].function_conflicts.conflicts[me]}
        + {/section} +
        + {/if} + +
        +{/section} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/global.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/global.tpl new file mode 100644 index 00000000..3c89ddfc --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/global.tpl @@ -0,0 +1,26 @@ +{section name=glob loop=$globals} + +
        + +
        + + {$globals[glob].global_type} + {$globals[glob].global_name} + {if $vars[vars].var_default} = {$globals[glob].global_value|replace:"\n":"
        "}
        {/if} + (line {if $globals[glob].slink}{$globals[glob].slink}{else}{$globals[glob].line_number}{/if}) +
        +
        + + {include file="docblock.tpl" sdesc=$globals[glob].sdesc desc=$globals[glob].desc tags=$globals[glob].tags} + + {if $globals[glob].global_conflicts.conflict_type} +
        +
        Conflicts with global variables:
        + {section name=me loop=$globals[glob].global_conflicts.conflicts} + {$globals[glob].global_conflicts.conflicts[me]}
        + {/section} +
        + {/if} + +
        +{/section} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/header.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/header.tpl new file mode 100644 index 00000000..d5e26dfa --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/header.tpl @@ -0,0 +1,12 @@ + + + + + + {$title} + + + + + {if $top3}
        {/if} + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/include.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/include.tpl new file mode 100644 index 00000000..bd408aff --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/include.tpl @@ -0,0 +1,16 @@ +{section name=includes loop=$includes} + +
        + +
        + + {$includes[includes].include_name} + ({$includes[includes].include_value}) + (line {if $includes[includes].slink}{$includes[includes].slink}{else}{$includes[includes].line_number}{/if}) + +
        + + {include file="docblock.tpl" sdesc=$includes[includes].sdesc desc=$includes[includes].desc tags=$includes[includes].tags} + +
        +{/section} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/index.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/index.tpl new file mode 100644 index 00000000..477d2b17 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/index.tpl @@ -0,0 +1,24 @@ + + + + + + {$title} + + + + + + + + + + + <H2>Frame Alert</H2> + <P>This document is designed to be viewed using the frames feature. + If you see this message, you are using a non-frame-capable web client.</P> + + + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/left_frame.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/left_frame.tpl new file mode 100644 index 00000000..4232d845 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/left_frame.tpl @@ -0,0 +1,149 @@ +{include file="header.tpl" top2=true} +
        {$package}
        +
        + +
        + +
        Description
        +
        + Class trees
        + Index of elements
        + {if $hastodos} + Todo List
        + {/if} +
        + + {section name=p loop=$info} + + {if $info[p].subpackage == ""} + + {if $info[p].tutorials} +
        Tutorials/Manuals
        +
        + {if $info[p].tutorials.pkg} +
        +
        Package-level
        +
        + {section name=ext loop=$info[p].tutorials.pkg} + {$info[p].tutorials.pkg[ext]} + {/section} +
        +
        + {/if} + + {if $info[p].tutorials.cls} +
        +
        Class-level
        +
        + {section name=ext loop=$info[p].tutorials.cls} + {$info[p].tutorials.cls[ext]} + {/section} +
        +
        + {/if} + + {if $info[p].tutorials.proc} +
        +
        Function-level
        +
        + {section name=ext loop=$info[p].tutorials.proc} + {$info[p].tutorials.proc[ext]} + {/section} +
        +
        + {/if} +
        + {/if} + {if $info[p].classes} +
        Classes
        + {section name=class loop=$info[p].classes} +
        {$info[p].classes[class].title}
        + {/section} + {/if} + {if $info[p].functions} +
        Functions
        + {section name=f loop=$info[p].functions} +
        {$info[p].functions[f].title}
        + {/section} + {/if} + {if $info[p].files} +
        Files
        + {section name=nonclass loop=$info[p].files} +
        {$info[p].files[nonclass].title}
        + {/section} + {/if} + + {else} + {if $info[p].tutorials} +
        Tutorials/Manuals
        +
        + {if $info[p].tutorials.pkg} +
        +
        Package-level
        +
        + {section name=ext loop=$info[p].tutorials.pkg} + {$info[p].tutorials.pkg[ext]} + {/section} +
        +
        + {/if} + + {if $info[p].tutorials.cls} +
        +
        Class-level
        +
        + {section name=ext loop=$info[p].tutorials.cls} + {$info[p].tutorials.cls[ext]} + {/section} +
        +
        + {/if} + + {if $info[p].tutorials.proc} +
        +
        Function-level
        +
        + {section name=ext loop=$info[p].tutorials.proc} + {$info[p].tutorials.proc[ext]} + {/section} +
        +
        + {/if} +
        + {/if} + +
        {$info[p].subpackage}
        +
        +
        + {if $info[p].subpackagetutorial} + + {/if} + {if $info[p].classes} +
        Classes
        + {section name=class loop=$info[p].classes} +
        {$info[p].classes[class].title}
        + {/section} + {/if} + {if $info[p].functions} +
        Functions
        + {section name=f loop=$info[p].functions} +
        {$info[p].functions[f].title}
        + {/section} + {/if} + {if $info[p].files} +
        Files
        + {section name=nonclass loop=$info[p].files} +
        {$info[p].files[nonclass].title}
        + {/section} + {/if} +
        +
        + + {/if} + + {/section} +
        +
        +

        phpDocumentor v {$phpdocversion}

        + + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/media/banner.css b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/media/banner.css new file mode 100644 index 00000000..e67227b7 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/media/banner.css @@ -0,0 +1,32 @@ +body +{ + background-color: #CCCCFF; + margin: 0px; + padding: 0px; +} + +/* Banner (top bar) classes */ + +.banner { } + +.banner-menu +{ + clear: both; + padding: .5em; + border-top: 2px solid #6666AA; +} + +.banner-title +{ + text-align: right; + font-size: 20pt; + font-weight: bold; + margin: .2em; +} + +.package-selector +{ + background-color: #AAAADD; + border: 1px solid black; + color: yellow; +} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/media/stylesheet.css b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/media/stylesheet.css new file mode 100644 index 00000000..88f471f2 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/media/stylesheet.css @@ -0,0 +1,144 @@ +a { color: #336699; text-decoration: none; } +a:hover { color: #6699CC; text-decoration: underline; } +a:active { color: #6699CC; text-decoration: underline; } + +body { background : #FFFFFF; } +body, table { font-family: Georgia, Times New Roman, Times, serif; font-size: 10pt } +p, li { line-height: 140% } +a img { border: 0px; } +dd { margin-left: 0px; padding-left: 1em; } + +/* Page layout/boxes */ + +.info-box {} +.info-box-title { margin: 1em 0em 0em 0em; padding: .25em; font-weight: normal; font-size: 14pt; border: 2px solid #999999; background-color: #CCCCFF } +.info-box-body { border: 1px solid #999999; padding: .5em; } +.nav-bar { font-size: 8pt; white-space: nowrap; text-align: right; padding: .2em; margin: 0em 0em 1em 0em; } + +.oddrow { background-color: #F8F8F8; border: 1px solid #AAAAAA; padding: .5em; margin-bottom: 1em} +.evenrow { border: 1px solid #AAAAAA; padding: .5em; margin-bottom: 1em} + +.page-body { max-width: 800px; margin: auto; } +.tree dl { margin: 0px } + +/* Index formatting classes */ + +.index-item-body { margin-top: .5em; margin-bottom: .5em} +.index-item-description { margin-top: .25em } +.index-item-details { font-weight: normal; font-style: italic; font-size: 8pt } +.index-letter-section { background-color: #EEEEEE; border: 1px dotted #999999; padding: .5em; margin-bottom: 1em} +.index-letter-title { font-size: 12pt; font-weight: bold } +.index-letter-menu { text-align: center; margin: 1em } +.index-letter { font-size: 12pt } + +/* Docbook classes */ + +.description {} +.short-description { font-weight: bold; color: #666666; } +.tags { padding-left: 0em; margin-left: 3em; color: #666666; list-style-type: square; } +.parameters { padding-left: 0em; margin-left: 3em; font-style: italic; list-style-type: square; } +.redefinitions { font-size: 8pt; padding-left: 0em; margin-left: 2em; } +.package { } +.package-title { font-weight: bold; font-size: 14pt; border-bottom: 1px solid black } +.package-details { font-size: 85%; } +.sub-package { font-weight: bold; font-size: 120% } +.tutorial { border-width: thin; border-color: #0066ff } +.tutorial-nav-box { width: 100%; border: 1px solid #999999; background-color: #F8F8F8; } +.nav-button-disabled { color: #999999; } +.nav-button:active, +.nav-button:focus, +.nav-button:hover { background-color: #DDDDDD; outline: 1px solid #999999; text-decoration: none } +.folder-title { font-style: italic } + +/* Generic formatting */ + +.field { font-weight: bold; } +.detail { font-size: 8pt; } +.notes { font-style: italic; font-size: 8pt; } +.separator { background-color: #999999; height: 2px; } +.warning { color: #FF6600; } +.disabled { font-style: italic; color: #999999; } + +/* Code elements */ + +.line-number { } + +.class-table { width: 100%; } +.class-table-header { border-bottom: 1px dotted #666666; text-align: left} +.class-name { color: #000000; font-weight: bold; } + +.method-summary { padding-left: 1em; font-size: 8pt } +.method-header { } +.method-definition { margin-bottom: .3em } +.method-title { font-weight: bold; } +.method-name { font-weight: bold; } +.method-signature { font-size: 85%; color: #666666; margin: .5em 0em } +.method-result { font-style: italic; } + +.var-summary { padding-left: 1em; font-size: 8pt; } +.var-header { } +.var-title { margin-bottom: .3em } +.var-type { font-style: italic; } +.var-name { font-weight: bold; } +.var-default {} +.var-description { font-weight: normal; color: #000000; } + +.include-title { } +.include-type { font-style: italic; } +.include-name { font-weight: bold; } + +.const-title { } +.const-name { font-weight: bold; } + +/* Syntax highlighting */ + +.src-code { border: 1px solid #336699; padding: 1em; background-color: #EEEEEE; } +*[class="src-code"] { line-height : 0.5em } + +.src-comm { color: green; } +.src-id { } +.src-inc { color: #0000FF; } +.src-key { color: #0000FF; } +.src-num { color: #CC0000; } +.src-str { color: #66cccc; } +.src-sym { font-weight: bold; } +.src-var { } + +.src-php { font-weight: bold; } + +.src-doc { color: #009999 } +.src-doc-close-template { color: #0000FF } +.src-doc-coretag { color: #0099FF; font-weight: bold } +.src-doc-inlinetag { color: #0099FF } +.src-doc-internal { color: #6699cc } +.src-doc-tag { color: #0080CC } +.src-doc-template { color: #0000FF } +.src-doc-type { font-style: italic } +.src-doc-var { font-style: italic } + +.tute-tag { color: #009999 } +.tute-attribute-name { color: #0000FF } +.tute-attribute-value { color: #0099FF } +.tute-entity { font-weight: bold; } +.tute-comment { font-style: italic } +.tute-inline-tag { color: #636311; font-weight: bold } + +/* tutorial */ + +.authors { } +.author { font-style: italic; font-weight: bold } +.author-blurb { margin: .5em 0em .5em 2em; font-size: 85%; font-weight: normal; font-style: normal } +.example { border: 1px dashed #999999; background-color: #EEEEEE; padding: .5em; } +*[class="example"] { line-height : 0.5em } +.listing { border: 1px dashed #999999; background-color: #EEEEEE; padding: .5em; white-space: nowrap; } +*[class="listing"] { line-height : 0.5em } +.release-info { font-size: 85%; font-style: italic; margin: 1em 0em } +.ref-title-box { } +.ref-title { } +.ref-purpose { font-style: italic; color: #666666 } +.ref-synopsis { } +.title { font-weight: bold; margin: 1em 0em 0em 0em; padding: .25em; border: 2px solid #999999; background-color: #CCCCFF } +.cmd-synopsis { margin: 1em 0em } +.cmd-title { font-weight: bold } +.toc { margin-left: 2em; padding-left: 0em } + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/method.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/method.tpl new file mode 100644 index 00000000..3138a925 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/method.tpl @@ -0,0 +1,61 @@ + +{section name=methods loop=$methods} + +
        + +
        + {if $methods[methods].ifunction_call.constructor}Constructor {elseif $methods[methods].ifunction_call.destructor}Destructor {/if}{$methods[methods].function_name} (line {if $methods[methods].slink}{$methods[methods].slink}{else}{$methods[methods].line_number}{/if}) +
        + + {include file="docblock.tpl" sdesc=$methods[methods].sdesc desc=$methods[methods].desc tags=$methods[methods].tags params=$methods[methods].params function=false} + +
        + {$methods[methods].function_return} + + {if $methods[methods].ifunction_call.returnsref}&{/if}{$methods[methods].function_name} + + {if count($methods[methods].ifunction_call.params)} + ({section name=params loop=$methods[methods].ifunction_call.params}{if $smarty.section.params.iteration != 1}, {/if}{if $methods[methods].ifunction_call.params[params].default}[{/if}{$methods[methods].ifunction_call.params[params].type} {$methods[methods].ifunction_call.params[params].name}{if $methods[methods].ifunction_call.params[params].default} = {$methods[methods].ifunction_call.params[params].default}]{/if}{/section}) + {else} + () + {/if} +
        + + {if $methods[methods].params} +
          + {section name=params loop=$methods[methods].params} +
        • + {$methods[methods].params[params].datatype} + {$methods[methods].params[params].var}{if $methods[methods].params[params].data}: {$methods[methods].params[params].data}{/if} +
        • + {/section} +
        + {/if} + + {if $methods[methods].method_overrides} +
        +
        Redefinition of:
        +
        +
        {$methods[methods].method_overrides.link}
        + {if $methods[methods].method_overrides.sdesc} +
        {$methods[methods].method_overrides.sdesc}
        + {/if} +
        + {/if} + + {if $methods[methods].descmethod} +
        +
        Redefined in descendants as:
        +
          + {section name=dm loop=$methods[methods].descmethod} +
        • + {$methods[methods].descmethod[dm].link} + {if $methods[methods].descmethod[dm].sdesc} + : {$methods[methods].descmethod[dm].sdesc} + {/if} +
        • + {/section} +
        + {/if} +
        +{/section} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/page.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/page.tpl new file mode 100644 index 00000000..e5e1913c --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/page.tpl @@ -0,0 +1,211 @@ +{include file="header.tpl" top3=true} + +

        {$source_location}

        + + +
        +
        Description
        + +
        + {include file="docblock.tpl" desc=$desc sdesc=$sdesc tags=$tags} + + {if $tutorial} +
        +
        Tutorial: {$tutorial}
        + {/if} +
        +
        + +{if $classes} + +
        +
        Classes
        + +
        + + + + + + {section name=classes loop=$classes} + + + + + {/section} +
        ClassDescription
        + {$classes[classes].link} + + {if $classes[classes].sdesc} + {$classes[classes].sdesc} + {else} + {$classes[classes].desc} + {/if} +
        +
        +
        +{/if} + +{if $includes} + +
        +
        Includes
        + +
        + {include file="include.tpl"} +
        +
        +{/if} + +{if $defines} + +
        +
        Constants
        + +
        + {include file="define.tpl"} +
        +
        +{/if} + +{if $globals} + +
        +
        Variables
        + +
        + {include file="global.tpl"} +
        +
        +{/if} + +{if $functions} + +
        +
        Functions
        + +
        + {include file="function.tpl"} +
        +
        +{/if} + +{include file="footer.tpl" top3=true} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/pkgelementindex.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/pkgelementindex.tpl new file mode 100644 index 00000000..542af8ed --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/pkgelementindex.tpl @@ -0,0 +1,17 @@ +{include file="header.tpl"} + +

        [{$package}] element index

        +{if count($packageindex) > 1} +

        Package indexes

        +
          + {section name=p loop=$packageindex} + {if $packageindex[p].title != $package} +
        • {$packageindex[p].title}
        • + {/if} + {/section} +
        +{/if} +All elements +
        +{include file="basicindex.tpl" indexname=elementindex_$package} +{include file="footer.tpl"} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/ric.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/ric.tpl new file mode 100644 index 00000000..c4cb83f9 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/ric.tpl @@ -0,0 +1,6 @@ +{include file="header.tpl"} +

        {$name}

        +
        +{$contents|htmlentities}
        +
        +{include file="footer.tpl"} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/todolist.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/todolist.tpl new file mode 100644 index 00000000..5ab0bca2 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/todolist.tpl @@ -0,0 +1,14 @@ +{include file="header.tpl" title="Todo List"} +

        Todo List

        +{foreach from=$todos key=todopackage item=todo} +

        {$todopackage}

        +{section name=todo loop=$todo} +

        {$todo[todo].link}

        +
          +{section name=t loop=$todo[todo].todos} +
        • {$todo[todo].todos[t]}
        • +{/section} +
        +{/section} +{/foreach} +{include file="footer.tpl"} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/top_frame.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/top_frame.tpl new file mode 100644 index 00000000..31f559cb --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/top_frame.tpl @@ -0,0 +1,43 @@ + + + + + + {$title} + + + + + + + + \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/tutorial.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/tutorial.tpl new file mode 100644 index 00000000..deb1ee04 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/tutorial.tpl @@ -0,0 +1,13 @@ +{include file="header.tpl" title=$title top3=true} + +{if $nav} + {include file="tutorial_nav.tpl" prev=$prev next=$next up=$up prevtitle=$prevtitle nexttitle=$nexttitle uptitle=$uptitle} +{/if} + +{$contents} + +{if $nav} + {include file="tutorial_nav.tpl" prev=$prev next=$next up=$up prevtitle=$prevtitle nexttitle=$nexttitle uptitle=$uptitle} +{/if} + +{include file="footer.tpl" top3=true} \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/tutorial_nav.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/tutorial_nav.tpl new file mode 100644 index 00000000..9b42fec8 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/tutorial_nav.tpl @@ -0,0 +1,41 @@ + + + + + + + + + + + +
        + {if $prev} + Previous + {else} + Previous + {/if} + + {if $up} + Up + {/if} + + {if $next} + Next + {else} + Next + {/if} +
        + {if $prevtitle} + {$prevtitle} + {/if} + + {if $uptitle} + {$uptitle} + {/if} + + {if $nexttitle} + {$nexttitle} + {/if} +
        + \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/tutorial_toc.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/tutorial_toc.tpl new file mode 100644 index 00000000..314ebd81 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/tutorial_toc.tpl @@ -0,0 +1,39 @@ +{if count($toc)} +

        Table of Contents

        +
          + {assign var="lastcontext" value='refsect1'} + {section name=toc loop=$toc} + + {if $toc[toc].tagname != $lastcontext} + {if $lastcontext == 'refsect1'} +
            +
          • {$toc[toc].link}
          • + {else} + {if $lastcontext == 'refsect2'} + {if $toc[toc].tagname == 'refsect1'} +
          +
        • {$toc[toc].link}
        • + {/if} + {if $toc[toc].tagname == 'refsect3'} +
            +
          • {$toc[toc].link}
          • + {/if} + {else} +
          +
        • {$toc[toc].link}
        • + {/if} + {/if} + {assign var="lastcontext" value=$toc[toc].tagname} + {else} +
        • {$toc[toc].link}
        • + {/if} + {/section} + {if $lastcontext == 'refsect2'} +
        + {/if} + {if $lastcontext == 'refsect3'} + + + {/if} + +{/if} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/tutorial_tree.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/tutorial_tree.tpl new file mode 100644 index 00000000..d5a18355 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/tutorial_tree.tpl @@ -0,0 +1,6 @@ + +{if $haskids} +
        + {$kids} +
        +{/if} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/var.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/var.tpl new file mode 100644 index 00000000..59c4d8cd --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/default/templates/var.tpl @@ -0,0 +1,44 @@ +{section name=vars loop=$vars} + +
        + +
        + + {$vars[vars].var_type} + {$vars[vars].var_name} + {if $vars[vars].var_default} = {$vars[vars].var_default|replace:"\n":"
        "}
        {/if} + (line {if $vars[vars].slink}{$vars[vars].slink}{else}{$vars[vars].line_number}{/if}) +
        +
        + + {include file="docblock.tpl" sdesc=$vars[vars].sdesc desc=$vars[vars].desc tags=$vars[vars].tags} + + {if $vars[vars].var_overrides} +
        +
        Redefinition of:
        +
        +
        {$vars[vars].var_overrides.link}
        + {if $vars[vars].var_overrides.sdesc} +
        {$vars[vars].var_overrides.sdesc}
        + {/if} +
        + {/if} + + {if $vars[vars].descvar} +
        +
        Redefined in descendants as:
        +
          + {section name=vm loop=$vars[vars].descvar} +
        • + {$vars[vars].descvar[vm].link} + {if $vars[vars].descvar[vm].sdesc} + : {$vars[vars].descvar[vm].sdesc} + {/if} +
        • + {/section} +
        + {/if} + +
        +{/section} + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/DescHTML.inc b/buildscripts/PhpDocumentor/phpDocumentor/DescHTML.inc new file mode 100644 index 00000000..f4fa31d3 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/DescHTML.inc @@ -0,0 +1,241 @@ +> in a description + * @package phpDocumentor + * @subpackage DescHTML + */ +class parserCode extends parserStringWithInlineTags +{ + /** + * @param Converter + * @uses Converter::ProgramExample() + */ + function Convert(&$c) + { + if (!isset($this->value[0])) return ''; + if (is_string($this->value[0]) && $this->value[0]{0} == "\n") + { + $this->value[0] = substr($this->value[0],1); + } + $linktags = array(); + foreach($this->value as $val) { + if (phpDocumentor_get_class($val) == 'parserlinkinlinetag' || + phpDocumentor_get_class($val) == 'parsertutorialinlinetag') { + $linktags[] = array($c->postProcess($val->Convert($c, false, false)), $val); + } + } + $a = $c->ProgramExample(rtrim(ltrim(parent::Convert($c, false, false), "\n\r"))); + foreach ($linktags as $tag) { + $a = str_replace($tag[0], $tag[1]->Convert($c, false, false), $a); + } + return $a; +// else return $c->PreserveWhiteSpace($this->getString(false)); + } +} + +/** + * Used for <
        > in a description
        + * @package phpDocumentor
        + * @subpackage DescHTML
        + */
        +class parserPre extends parserStringWithInlineTags
        +{
        +    /**
        +     * @param Converter
        +     * @uses Converter::PreserveWhiteSpace()
        +     */
        +    function Convert(&$c)
        +    {
        +        return $c->PreserveWhiteSpace(rtrim(ltrim(parent::Convert($c, false, false), "\n\r")));
        +    }
        +}
        +
        +/**
        + * Used for <> in a description
        + * @package phpDocumentor
        + * @subpackage DescHTML
        + */
        +class parserB extends parserStringWithInlineTags
        +{
        +    /**
        +     * @param Converter
        +     * @uses Converter::Bolden()
        +     */
        +    function Convert(&$c)
        +    {
        +        return $c->Bolden(parent::Convert($c));
        +    }
        +}
        +
        +/**
        + * Used for <> in a description
        + * @package phpDocumentor
        + * @subpackage DescHTML
        + */
        +class parserI extends parserStringWithInlineTags
        +{
        +    /**
        +     * @param Converter
        +     * @uses Converter::Italicize()
        +     */
        +    function Convert(&$c)
        +    {
        +        return $c->Italicize(parent::Convert($c));
        +    }
        +}
        +
        +/**
        + * Used for <> in a description
        + * @package phpDocumentor
        + * @subpackage DescHTML
        + */
        +class parserDescVar extends parserStringWithInlineTags
        +{
        +    /**
        +     * @param Converter
        +     * @uses Converter::Varize()
        +     */
        +    function Convert(&$c)
        +    {
        +        return $c->Varize(parent::Convert($c));
        +    }
        +}
        +
        +/**
        + * Used for <> in a description
        + * @package phpDocumentor
        + * @subpackage DescHTML
        + */
        +class parserSamp extends parserStringWithInlineTags
        +{
        +    /**
        +     * @param Converter
        +     * @uses Converter::Sampize()
        +     */
        +    function Convert(&$c)
        +    {
        +        return $c->Sampize(parent::Convert($c));
        +    }
        +}
        +
        +/**
        + * Used for <> in a description
        + * @package phpDocumentor
        + * @subpackage DescHTML
        + */
        +class parserKbd extends parserStringWithInlineTags
        +{
        +    /**
        +     * @param Converter
        +     * @uses Converter::Kbdize()
        +     */
        +    function Convert(&$c)
        +    {
        +        return $c->Kbdize(parent::Convert($c));
        +    }
        +}
        +
        +/**
        + * Used for <
        > in a description + * @package phpDocumentor + * @subpackage DescHTML + */ +class parserBr extends parserStringWithInlineTags +{ + /** + * @param Converter + * @uses Converter::Br() + */ + function Convert(&$c) + { + return $c->Br($this->getString()); + } +} + +/** + * Used for lists <
          > and <
            > + * @package phpDocumentor + * @subpackage DescHTML + */ +class parserList extends parserStringWithInlineTags +{ + /** @var boolean */ + var $numbered; + /** @var integer */ + var $items = 0; + /** + * @param integer + */ + function parserList($numbered) + { + $this->numbered = $numbered; + } + + /** @param parserStringWithInlineTags */ + function addItem($item) + { + $this->value[$this->items++] = $item; + } + + /** @param parserList */ + function addList($list) + { + $this->value[$this->items++] = $list; + } + + /** + * @uses Converter::ListItem() enclose each item of the list + * @uses Converter::EncloseList() enclose the list + * @param Converter + */ + function Convert(&$c) + { + $list = ''; + foreach($this->value as $item) + { + $list .= $c->ListItem(trim($item->Convert($c))); + } + return $c->EncloseList($list,$this->numbered); + } +} + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/DocBlock/Lexer.inc b/buildscripts/PhpDocumentor/phpDocumentor/DocBlock/Lexer.inc new file mode 100644 index 00000000..edfc896c --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/DocBlock/Lexer.inc @@ -0,0 +1,701 @@ +tokens = array( + PHPDOC_DOCBLOCK_TOKEN_NEWLINE => 'PHPDOC_DOCBLOCK_TOKEN_NEWLINE', + PHPDOC_DOCBLOCK_TOKEN_DESC => 'PHPDOC_DOCBLOCK_TOKEN_DESC', + PHPDOC_DOCBLOCK_TOKEN_ESCTAGOPEN => 'PHPDOC_DOCBLOCK_TOKEN_ESCTAGOPEN', + PHPDOC_DOCBLOCK_TOKEN_ESCTAGCLOSE => 'PHPDOC_DOCBLOCK_TOKEN_ESCTAGCLOSE', + PHPDOC_DOCBLOCK_TOKEN_TAG => 'PHPDOC_DOCBLOCK_TOKEN_TAG', + PHPDOC_DOCBLOCK_TOKEN_INLINETAG => 'PHPDOC_DOCBLOCK_TOKEN_INLINETAG', + PHPDOC_DOCBLOCK_TOKEN_INLINETAGCLOSE => 'PHPDOC_DOCBLOCK_TOKEN_INLINETAGCLOSE', + PHPDOC_DOCBLOCK_TOKEN_INTERNAL => 'PHPDOC_DOCBLOCK_TOKEN_INTERNAL', + PHPDOC_DOCBLOCK_TOKEN_INTERNALCLOSE => 'PHPDOC_DOCBLOCK_TOKEN_INTERNALCLOSE', + ); + if (in_array($token, array_keys($this->tokens))) { + return $this->tokens[$token]; + } + return 'UNKNOWN'; + } + + function lex($comment) + { + $comment = str_replace(array("\r\n", "\r"), array("\n", "\n"), $comment); + $comment = explode("\n", $comment); + $this->tokens = array(); + $state = PHPDOC_LEXER_DESC; + $this->states = array(PHPDOC_LEXER_DESC); + $tid = 0; + $token = ''; + $esctag = false; + $this->exception = false; + list($lastline,) = each(array_reverse($comment, true)); + foreach ($comment as $this->linenum => $line) { + if ($this->exception) { + $this->tokens = array(); + return false; + } + $linestart = true; + $this->processedline = trim($line); + if ($this->processedline == '*/') { + break; + } + if (!$this->processedline) { + continue; + } + if (substr($this->processedline, 0, 3) == '/**') { + $this->processedline = substr($this->processedline, 3); + if (!$this->processedline) { + continue; + } + if (trim($this->processedline) == '*/') { + $this->endSimpleList(); + break; + } + } else { + $this->processedline = substr($this->processedline, 1); + } + while (true) { + switch ($state) { + case PHPDOC_LEXER_INTERNALTAG : + $internalendpos = strpos($this->processedline, '}}'); + case PHPDOC_LEXER_TAGS : + $trimline = trim($this->processedline); + if (strlen($trimline) && $trimline{0} == '@') { + if (preg_match('/^(@[^\s]+)\s/', $trimline, $matches) || + preg_match('/^(@[^\s]+)$/', $trimline, $matches)) { + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_TAG, + $matches[1]); + $this->processedline = substr($trimline, strpos($trimline, $matches[1]) + + strlen($matches[1])); + if (!$this->processedline) { + break 2; + } + continue 2; // to while(true) + } + } elseif (preg_match('/^@/', $trimline, $matches)) { + // throw exception for invalid tag + return $this->throwException('Invalid tag encountered in line number ' . + $this->linenum . ': "' . $line . '"', 'tag'); + } else { + $tagpos = strpos($this->processedline, '<'); + $inlinetagpos = strpos($this->processedline, '{@'); + if (isset($internalendpos) && $internalendpos !== false) { + do { + if ($tagpos !== false && $internalendpos > $tagpos) { + break; + } + if ($inlinetagpos !== false && $internalendpos > $inlinetagpos) { + break; + } + // }} is the next important token + $this->appendDesc(substr($this->processedline, 0, + $internalendpos)); + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_INTERNALCLOSE, '}}'); + $this->processedline = substr($this->processedline, $internalendpos + + 2); + array_shift($this->states); + $state = PHPDOC_LEXER_TAGS; + continue 3; // to while(true); + } while (false); + } + if ($tagpos !== false && $inlinetagpos !== false) { + if ($tagpos > $inlinetagpos) { + $tagpos = false; + } else { + $inlinetagpos = false; + } + } + if ($tagpos !== false) { + continue $this->searchForHTMLTag($tagpos, + $state, $esctag, $linestart, $trimline); + } + if ($inlinetagpos !== false) { + $state = $this->searchForInlineTag($inlinetagpos, $comment); + $linestart = false; + continue 2; // to while (true) + } + if (strpos($this->processedline, '*/')) { + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_DESC, + substr($this->processedline, + 0, strpos($this->processedline, '*/'))); + return $this->tokens; + } + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_DESC, $this->processedline); + } + break; + case PHPDOC_LEXER_INTERNAL : + $internalendpos = strpos($this->processedline, '}}'); + case PHPDOC_LEXER_SIMPLELIST : + if ($linestart && $state == PHPDOC_LEXER_SIMPLELIST) { + if (!$this->processSimpleList()) { + while (count($this->simplelist) && !$this->processSimpleList()); + } + if (!count($this->simplelist)) { + array_shift($this->states); + $state = array_shift($this->states); + array_unshift($this->states, $state); + } + } + case PHPDOC_LEXER_DESC : + if (strpos($this->processedline, '*/')) { + $this->processedline = substr($this->processedline, + 0, strpos($this->processedline, '*/')); + } + if (!$this->processedline) { + if ($this->linenum != $lastline) { + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_NEWLINE, "\n"); + } + continue 3; // to foreach + } + $trimline = trim($this->processedline); + if ($linestart && $state != PHPDOC_LEXER_TAGS && $trimline{0} == '@') { + if ($state == PHPDOC_LEXER_INTERNAL) { + // throw exception + return $this->throwException('Cannot start tags in {@internal}} ' . + ' in line number ' . + $this->linenum . ': "' . $line . '"', 'tag'); + } + $this->states = array(PHPDOC_LEXER_TAGS); + $state = PHPDOC_LEXER_TAGS; + continue 2; // to while(true) + + } + if ($state != PHPDOC_LEXER_SIMPLELIST && $linestart && strlen($trimline) > 3 && + ($trimline{0} == '-' || $trimline{0} == '*' || + $trimline{0} == '#' || $trimline{0} == 'o' || + $trimline{0} == '1')) { + if ($this->searchForSimplelist($trimline)) { + $state = PHPDOC_LEXER_SIMPLELIST; + $linestart = false; + continue 2; // to while(true) + } + } + $tagpos = strpos($this->processedline, '<'); + $inlinetagpos = strpos($this->processedline, '{@'); + if (isset($internalendpos) && $internalendpos !== false) { + do { + if ($tagpos !== false && $internalendpos > $tagpos) { + break; + } + if ($inlinetagpos !== false && $internalendpos > $inlinetagpos) { + break; + } + // }} is the next important token + $this->appendDesc(substr($this->processedline, 0, $internalendpos)); + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_INTERNALCLOSE, '}}'); + $this->processedline = substr($this->processedline, $internalendpos + + 2); + array_shift($this->states); + $state = PHPDOC_LEXER_DESC; + continue 3; // to while(true); + } while (false); + } + if ($tagpos !== false && $inlinetagpos !== false) { + if ($tagpos > $inlinetagpos) { + $tagpos = false; + } else { + $inlinetagpos = false; + } + } + if ($tagpos !== false) { + continue $this->searchForHTMLTag($tagpos, $state, + $esctag, $linestart, $trimline); + } + if ($inlinetagpos !== false) { + $state = $this->searchForInlineTag($inlinetagpos, $comment); + $linestart = false; + continue 2; // to while (true) + } + $this->appendDesc($this->processedline); + break; + case PHPDOC_LEXER_ESCTAG : + if (!$this->processedline) { + if ($this->linenum != $lastline) { + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_NEWLINE, "\n"); + } + continue 3; // to foreach + } + $endpos = strpos($this->processedline, $esctag); + $inlinetagpos = strpos($this->processedline, '{@'); + if ($endpos !== false && $inlinetagpos !== false) { + if ($endpos > $inlinetagpos) { + $endpos = false; + } else { + $inlinetagpos = false; + } + } + if ($endpos !== false) { + if (strlen(substr($this->processedline, 0, $endpos))) { + $this->appendDesc(substr($this->processedline, 0, $endpos)); + } + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ESCTAGCLOSE, $esctag); + $this->processedline = substr($this->processedline, $endpos + + strlen($esctag)); + $state = $this->states[0]; + if (count($this->states) > 1) { + array_shift($this->states); + } + if (!$this->processedline) { + break 2; + } + } + if ($inlinetagpos !== false) { + array_unshift($this->states, PHPDOC_LEXER_ESCTAG); + $state = $this->searchForInlineTag($inlinetagpos, $comment); + $linestart = false; + continue 2; // to while (true) + } + $this->appendDesc($this->processedline); + break; + case PHPDOC_LEXER_INLINETAG : + if (!$this->processedline) { + if ($this->linenum != $lastline) { + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_NEWLINE, "\n"); + } + continue 3; // to foreach + } + $endpos = strpos($this->processedline, '}'); + if ($endpos !== false) { + if (strlen(substr($this->processedline, 0, $endpos))) { + $this->appendDesc(substr($this->processedline, 0, $endpos)); + } + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_INLINETAGCLOSE, '}'); + $this->processedline = substr($this->processedline, $endpos + 1); // strlen('}') + $state = $this->states[0]; + if (count($this->states) > 1) { + array_shift($this->states); + } + if (!$this->processedline) { + break 2; + } + if ($state != PHPDOC_LEXER_INLINETAG && strlen($this->processedline)) { + $linestart = false; + continue 2; // to while (true) + } + } + $this->appendDesc($this->processedline); + break; + } + break; + } + if ($this->linenum != $lastline) { + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_NEWLINE, "\n"); + } + } + return $this->tokens; + } + + function searchForSimplelist($trimline) + { + $whitespace = strpos($this->processedline, $trimline); + switch ($trimline{0}) { + case '-' : + case '*' : + case '+' : + case 'o' : + if (strlen($trimline) < 3 || $trimline{1} != ' ') { + return false; + } + // unordered lists + $this->simplelist[] = 'u' . $trimline{0}; + $this->whitespace[] = $whitespace; + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTSTART, ''); + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_UNORDEREDBULLET, $trimline{0}); + $this->processedline = substr($this->processedline, strpos($this->processedline, + $trimline{0}) + 2); + array_unshift($this->states, PHPDOC_LEXER_SIMPLELIST); + return true; + break; + case '#' : + if (strlen($trimline) < 3) { + return false; + } + // ordered lists + $this->simplelist[] = '#1'; + $this->whitespace[] = $whitespace; + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTSTART, ''); + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ORDEREDBULLET, '#'); + $this->processedline = substr($this->processedline, strpos($this->processedline, + '#') + 2); + array_unshift($this->states, PHPDOC_LEXER_SIMPLELIST); + return true; + case '1' : + if (strlen($trimline) < 4) { + return false; + } + if ($trimline{1} == ' ') { + $this->simplelist[] = 'O1'; + } elseif ($trimline{1} == '.' && $trimline{2} == ' ') { + $this->simplelist[] = 'o1'; + } else { + return false; + } + $this->whitespace[] = $whitespace; + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTSTART, ''); + if ($trimline{1} == '.') { + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ORDEREDBULLET, '1.'); + $this->processedline = substr($this->processedline, strpos($this->processedline, + '1.') + 3); + } else { + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ORDEREDBULLET, '1'); + $this->processedline = substr($this->processedline, strpos($this->processedline, + '1') + 2); + } + array_unshift($this->states, PHPDOC_LEXER_SIMPLELIST); + return true; + } + return false; + } + + /** + * @todo process multi-line elements via whitespace + * @todo process nested simple lists + */ + function processSimpleList() + { + $trimline = trim($this->processedline); + $index = count($this->simplelist) - 1; + $whitespace = strpos($this->processedline, $trimline); + if ($whitespace < $this->whitespace[$index]) { + while (count($this->whitespace[$index]) && $whitespace < $this->whitespace[$index]) { + // the end of the current simplelist + $this->tokens = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTEND, ''); + array_pop($this->simplelist); + $index--; + } + if ($index == -1) { + return false; // all simple lists concluded + } + } + if ($whitespace > $this->whitespace[$index]) { + // could be a multi-line element or a new list + if (!$this->searchForSimplelist($trimline)) { + // trim off the simple list whitespace if this is multi-line + $this->processedline = substr($this->processedline, $this->whitespace[$index] + 2); + } + return true; + } + // implied: whitespace matches exactly so this is either another + // bullet point or the end of the simple list + switch ($this->simplelist[$index]{0}) { + case 'u' : + if (strlen($trimline) < 3 || $trimline{0} != $this->simplelist[$index]{1} || + $trimline{1} != ' ') { + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTEND, ''); + array_pop($this->simplelist); + return false; + } + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_UNORDEREDBULLET, $trimline{0}); + $this->processedline = substr($this->processedline, strpos($this->processedline, + $trimline{0}) + 2); + break; + case 'o' : + if (strlen($trimline) < 4 || ($trimline{0} != + ($this->simplelist[$index]{1} + 1) . '') || + $trimline{1} != '.' || $trimline{2} != ' ') { + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTEND, ''); + array_pop($this->simplelist); + return false; + } + $this->simplelist[$index] = $this->simplelist[$index]{0} . + ($this->simplelist[$index]{1} + 1); + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ORDEREDBULLET, + $this->simplelist[$index]{1} . '.'); + $this->processedline = substr($this->processedline, strpos($this->processedline, + $trimline{0} . '.') + 3); + break; + case 'O' : + if (strlen($trimline) < 3 || $trimline{0} != ($this->simplelist[$index]{1} + 1) . '' || + $trimline{1} != ' ') { + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTEND, ''); + array_pop($this->simplelist); + return false; + } + $this->simplelist[$index] = $this->simplelist[$index]{0} . + ($this->simplelist[$index]{1} + 1); + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ORDEREDBULLET, + $this->simplelist[$index]{1}); + $this->processedline = substr($this->processedline, strpos($this->processedline, + $this->simplelist[$index]{1}) + 2); + break; + case '#' : + if (strlen($trimline) < 3 || $trimline{0} != '#' || + $trimline{1} != ' ') { + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTEND, ''); + array_pop($this->simplelist); + return false; + } + $this->simplelist[$index] = $this->simplelist[$index]{0} . + ($this->simplelist[$index]{1} + 1); + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ORDEREDBULLET, + $this->simplelist[$index]{1}); + $this->processedline = substr($this->processedline, strpos($this->processedline, + '#') + 2); + break; + } + return true; + } + + function searchForHTMLTag($tagpos, &$state, &$esctag, &$linestart, + &$trimline) + { + if (preg_match('/^<(<\/?[a-zA-Z]+ ?\/?>)>/', substr($this->processedline, $tagpos), + $matches)) { + if ($tagpos) { + $this->appendDesc(substr($this->processedline, 0, $tagpos)); + } + $this->appendDesc($matches[1]); + $this->processedline = substr($this->processedline, $tagpos + + strlen($matches[1]) + + 2); + return 2; + } elseif (!count($matches) && + preg_match('/^<(<\/?[a-zA-Z]+ ?\/?>)>/', substr($this->processedline, $tagpos + 1), + $matches)) { + if ($tagpos) { + $this->appendDesc(substr($this->processedline, 0, $tagpos)); + } + $this->appendDesc('<' . $matches[1]); + $this->processedline = substr($this->processedline, $tagpos + + strlen($matches[1]) + + 3); + return 2; + } elseif (preg_match('#^(br>|br/>|br />)#', + substr($this->processedline, $tagpos + 1), $matches)) { + if ($tagpos) { + $this->appendDesc(substr($this->processedline, 0, $tagpos)); + } + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_HTMLTAG, 'br'); + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_HTMLTAGCLOSE, 'br'); + $this->processedline = substr($this->processedline, $tagpos + + strlen($matches[1]) + + 1); + return 2; + } elseif (preg_match('/^(b>|i>|li>|ol>|ul>|p>|pre>|var>)/', + substr($this->processedline, $tagpos + 1), $matches)) { + if ($tagpos) { + $this->appendDesc(substr($this->processedline, 0, $tagpos)); + } + $matches = substr($matches[1], 0, strlen($matches[1]) - 1); + array_push($this->tagStack, $matches); + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_HTMLTAG, $matches); + $this->processedline = substr($this->processedline, $tagpos + + strlen($matches) + + 2); + return 2; + } elseif (preg_match('#^(/b>|/i>|/li>|/ol>|/ul>|/p>|/pre>|/var>)#', + substr($this->processedline, $tagpos + 1), $matches)) { + if ($tagpos) { + $this->appendDesc(substr($this->processedline, 0, $tagpos)); + } + $matches = substr($matches[1], 1, strlen($matches[1]) - 2); + $test = array_pop($this->tagStack); + if ($matches != $test) { + // throw exception + $this->throwException('Invalid closing html tag encountered in line number ' . + $this->linenum . ': "", expecting ""', 'htmltag'); + return 3; + } + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_HTMLTAGCLOSE, $matches); + $this->processedline = substr($this->processedline, $tagpos + + strlen($matches) + + 3); + return 2; + } elseif (preg_match('/^(code>|pre>|kbd>|samp>)/', + substr($this->processedline, $tagpos + 1), $matches)) { + $esctag = 'appendDesc(substr($this->processedline, 0, $tagpos)); + } + switch ($matches[0]) { + case 'code>' : + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ESCTAGOPEN, + ''); + break; + case 'pre>' : + $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ESCTAGOPEN, + '
            ');
            +                break;
            +                case 'kbd>' :
            +                    $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ESCTAGOPEN,
            +                        '');
            +                break;
            +                case 'samp>' :
            +                    $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_ESCTAGOPEN,
            +                        '');
            +                break;
            +            }
            +            $this->processedline = $line = substr($this->processedline, $tagpos
            +                + strlen($matches[0])
            +                + 1);
            +            $state = PHPDOC_LEXER_ESCTAG;
            +            if (!$this->processedline) {
            +                return 3; // to foreach
            +            }
            +            if (strpos($this->processedline, $esctag) !== false) {
            +                if (!strpos($this->processedline, $esctag)) {
            +                    $linestart = false;
            +                    return 2; // to while (true)
            +                }
            +                if (strpos($this->processedline, $esctag)) {
            +                    $this->appendDesc(substr($this->processedline, 0,
            +                        strpos($this->processedline, $esctag)));
            +                }
            +                $this->processedline = $trimline =
            +                    substr($this->processedline, strpos($this->processedline, $esctag));
            +                $linestart = false;
            +                return 2; // to while(true)
            +            }
            +        }
            +    }
            +
            +    function searchForInlineTag($inlinetagpos, $comment)
            +    {
            +        if ($inlinetagpos) {
            +            $this->appendDesc(substr($this->processedline, 0, $inlinetagpos));
            +        }
            +        if ($inlinetagpos === strpos($this->processedline, '{@internal')) {
            +            $state = array_shift($this->states);
            +            array_unshift($this->states, $state);
            +            if ($state == PHPDOC_LEXER_INTERNAL || $state == PHPDOC_LEXER_INTERNALTAG) {
            +                // throw exception
            +                return $this->throwException('cannot nest {@internal}} in line number ' .
            +                    $this->linenum . ': "' . $line . '"', 'internaltag');
            +            }
            +            $basestate = array_pop($this->states);
            +            array_push($this->states, $basestate);
            +            if ($basestate == PHPDOC_LEXER_DESC) {
            +                $newstate = PHPDOC_LEXER_INTERNAL;
            +            } else {
            +                $newstate = PHPDOC_LEXER_INTERNALTAG;
            +            }
            +            array_unshift($this->states, $newstate);
            +            $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_INTERNAL, '{@internal');
            +            $this->processedline = substr($this->processedline, $inlinetagpos + strlen('{@internal'));
            +            return $newstate;
            +        }
            +        if (!preg_match('/^({@[^}\s]+)\s/', substr($this->processedline, $inlinetagpos), $matches)) {
            +            if (!preg_match('/^({@[^}\s]+)}/', substr($this->processedline, $inlinetagpos), $matches)) {
            +                if ($this->hasEndchar($comment, '}')) {
            +                    $matches = array(substr($this->processedline, $inlinetagpos),
            +                        substr($this->processedline, $inlinetagpos));
            +                } else {
            +                    // throw exception if this does not match
            +                    $this->throwException('Unclosed inline tag encountered on line number ' .
            +                        $this->linenum . ': "' . $line . '"', 'tag');
            +                    return PHPDOC_LEXER_DESC;
            +                }
            +            } else {
            +                // throw exception if this does not match
            +                $this->throwException('Invalid inline tag encountered in line number ' .
            +                    $this->linenum . ': "' . $line . '"', 'tag');
            +                return PHPDOC_LEXER_DESC;
            +            }
            +        }
            +        $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_INLINETAG, $matches[1]);
            +        $this->processedline = substr($this->processedline, $inlinetagpos + strlen($matches[1]));
            +        return PHPDOC_LEXER_INLINETAG;
            +    }
            +
            +    function appendDesc($desc)
            +    {
            +        if (!strlen($desc)) {
            +            return;
            +        }
            +        if (count($this->tokens)) {
            +            $last = array_pop($this->tokens);
            +            if ($last[0] == PHPDOC_DOCBLOCK_TOKEN_DESC) {
            +                $last[1] .= $desc;
            +                $this->tokens[] = $last;
            +            } else {
            +                $this->tokens[] = $last;
            +                $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_DESC, $desc);
            +            }
            +        } else {
            +            $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_DESC, $desc);
            +        }
            +    }
            +
            +    function hasEndChar($comment, $char)
            +    {
            +        $linenum = $this->linenum;
            +        foreach ($comment as $num => $line) {
            +            if ($linenum !== false && $num <= $linenum) {
            +                continue;
            +            }
            +            $linenum = false;
            +            $processedline = trim($line);
            +            if ($processedline == '*/') {
            +                break;
            +            }
            +            if (!$processedline) {
            +                continue;
            +            }
            +            if (substr($processedline, 0, 3) == '/**') {
            +                $processedline = substr($processedline, 3);
            +                if (!$processedline) {
            +                    continue;
            +                }
            +                if (trim($processedline) == '*/') {
            +                    break;
            +                }
            +            } else {
            +                $processedline = substr($processedline, 1);
            +            }
            +            if (strpos($processedline, $char) !== false) {
            +                return true;
            +            }
            +        }
            +        return false;
            +    }
            +
            +    function endSimpleList()
            +    {
            +        if (count($this->tagStack)) {
            +            $this->tokens = array();
            +            return $this->throwException('Error: unclosed html tags: "' .
            +                implode(', ', $this->tagStack) . '"', 'simplelist');
            +        }
            +        while (count($this->simplelist)) {
            +            $this->tokens[] = array(PHPDOC_DOCBLOCK_TOKEN_SIMPLELISTEND, '');
            +        }
            +    }
            +
            +    function throwException($message, $type)
            +    {
            +        $this->error = array($message, $this->linenum, $type);
            +        $this->exception = true;
            +    }
            +}
            +?>
            \ No newline at end of file
            diff --git a/buildscripts/PhpDocumentor/phpDocumentor/DocBlockTags.inc b/buildscripts/PhpDocumentor/phpDocumentor/DocBlockTags.inc
            new file mode 100644
            index 00000000..fa465deb
            --- /dev/null
            +++ b/buildscripts/PhpDocumentor/phpDocumentor/DocBlockTags.inc
            @@ -0,0 +1,984 @@
            +
            + * @since 1.0rc1
            + * @version $Id: DocBlockTags.inc,v 1.1 2005/10/17 18:36:55 jeichorn Exp $
            + */
            +class parserTag extends parserStringWithInlineTags
            +{
            +    /**
            +     * Type is used by many functions to skip the hassle of if phpDocumentor_get_class($blah) == 'parserBlah'
            +     * always '_tag'
            +     * @var string
            +     */
            +    var $type = '_tag';
            +    /**
            +     * tag name (see, access, etc.)
            +     * @var string
            +     */
            +    var $keyword = '';
            +    
            +    /**
            +     * Set up the tag
            +     *
            +     * {@source}
            +     * @param string $keyword tag name
            +     * @param parserStringWithInlineTags $value
            +     * @param boolean whether to parse the $value for html tags
            +     */
            +    function parserTag($keyword, $value, $noparse = false)
            +    {
            +        $this->keyword = $keyword;
            +        if (!$noparse)
            +        {
            +            $parser = new parserDescParser;
            +            $parser->subscribe('*',$this);
            +            $parser->parse($value->value,true,'parserstringwithinlinetags');
            +        } else $this->value = $value;
            +    }
            +    
            +    /**
            +     * @param Converter
            +     * @see Converter
            +     */
            +    function Convert(&$converter)
            +    {
            +        if (is_array($this->value))
            +        {
            +            if (count($this->value) == 1)
            +            {
            +                list(,$val) = each($this->value);
            +                reset($this->value);
            +                return $val->Convert($converter);
            +            }
            +            $result = '';
            +            foreach($this->value as $val)
            +            {
            +                // this is only true if we processed the description in
            +                // the constructor
            +                if (phpDocumentor_get_class($val) == 'parserstringwithinlinetags')
            +                $result .= $converter->EncloseParagraph($val->Convert($converter));
            +                else
            +                $result .= $val->Convert($converter);
            +            }
            +            return $result;
            +        } else
            +        {
            +            return $this->value->Convert($converter);
            +        }
            +    }
            +    
            +    /**
            +     * Gets a count of the number of paragraphs in this
            +     * tag's description.
            +     *
            +     * Useful in determining whether to enclose the
            +     * tag in a paragraph or not.
            +     * @access private
            +     * @return integer
            +     */
            +    function _valueParagraphCount()
            +    {
            +    }
            +    
            +    /**
            +     * Called by the {@link parserDescParser} when processing a description.
            +     * @param integer not used
            +     * @param array array of {@link parserStringWithInlineTags} representing
            +     *              paragraphs in the tag description
            +     * @see parserTag::parserTag()
            +     */
            +    function HandleEvent($a,$desc)
            +    {
            +        $this->value = $desc;
            +    }
            +    
            +    /**
            +     * @return string returns the text minus any inline tags
            +     * @see parserStringWithInlineTags::getString()
            +     */
            +    function getString()
            +    {
            +        if (is_array($this->value))
            +        {
            +            $result = '';
            +            foreach($this->value as $val)
            +            {
            +                $result .= $val->getString();
            +            }
            +            return $result;
            +        } else return $this->value->getString();
            +    }
            +}
            +
            +/**
            + * This class represents the @name tag
            + * @tutorial tags.name.pkg
            + * @package phpDocumentor
            + * @subpackage DocBlockTags
            + */
            +class parserNameTag extends parserTag
            +{
            +    /**
            +     * tag name
            +     * @var string
            +     */
            +    var $keyword = 'name';
            +    
            +    /**
            +     * @param string not used
            +     * @param string name
            +     */
            +    function parserNameTag($name, $value)
            +    {
            +        $this->value = $value;
            +    }
            +    
            +    /**
            +     * @see parserStringWithInlineTags::Convert()
            +     * @param Converter
            +     * @return string converted value of the tag
            +     */
            +    function Convert(&$c)
            +    {
            +        return $this->value;
            +    }
            +}
            +
            +/**
            + * This class represents the @access tag
            + * @tutorial tags.access.pkg
            + * @package phpDocumentor
            + * @subpackage DocBlockTags
            + */
            +class parserAccessTag extends parserTag
            +{
            +    /**
            +     * tag name
            +     * @var string
            +     */
            +    var $keyword = 'access';
            +    
            +    /**
            +     * set to true if the returned tag has a value type of private, protected
            +     * or public, false otherwise
            +     * @var boolean
            +     */
            +    var $isvalid = false;
            +    
            +    /**
            +     * checks $value to make sure it is private, protected or public, otherwise
            +     * it's not a valid @access tag
            +     * @see $isvalid
            +     * @param parserStringWithInlineTags $value
            +     */
            +    function parserAccessTag($value)
            +    {
            +        if (!is_string($value))
            +        {
            +            if (is_object($value))
            +            {
            +                if (method_exists($value,'getstring'))
            +                {
            +                    $value = $value->getString();
            +                }
            +            }
            +        }
            +        switch(trim($value))
            +        {
            +            case 'private' :
            +            case 'public' :
            +            case 'protected' :
            +                $this->value = $value;
            +                $this->isvalid = true;
            +            break;
            +            default :
            +            addError(PDERROR_ACCESS_WRONG_PARAM,$value);
            +                $this->value = 'public';
            +            break;
            +        }
            +    }
            +    
            +    /**
            +     * @see parserStringWithInlineTags::Convert()
            +     * @param Converter
            +     * @return string converted value of the tag
            +     */
            +    function Convert(&$converter)
            +    {
            +        return $this->value;
            +    }
            +    
            +    /**
            +     * No inline tags are possible, returns 'public', 'protected' or 'private'
            +     * @return string returns the text minus any inline tags
            +     */
            +    function getString()
            +    {
            +        return $this->value;
            +    }
            +}
            +
            +/**
            + * represents "@return"
            + * @tutorial tags.return.pkg
            + * @package phpDocumentor
            + * @subpackage DocBlockTags
            + * @author Greg Beaver 
            + * @since 1.0rc1
            + * @version $Id: DocBlockTags.inc,v 1.1 2005/10/17 18:36:55 jeichorn Exp $
            + */
            +class parserReturnTag extends parserTag
            +{
            +    /**
            +     * always 'return'
            +     * @var string
            +     */
            +    var $keyword = 'return';
            +    /**
            +     * the type a function returns
            +     */
            +    var $returnType = 'void';
            +    
            +    /**
            +     * contains a link to the documentation for a class passed as a type in @return, @var or @param
            +     *
            +     * Example:
            +     *
            +     * 
            +     * class myclass
            +     * {
            +     * ...
            +     * }
            +     * /** @return myclass blahblahblah
            +     * ...
            +     * 
            +     *
            +     * In this case, $converted_returnType will contain a link to myclass instead of the string 'myclass'
            +     * @var mixed either the same as $returnType or a link to the docs for a class
            +     * @see $returnType
            +     */
            +    var $converted_returnType = false;
            +    
            +    /**
            +     * @param string
            +     * @param parserStringWithInlineTags
            +     */
            +    function parserReturnTag($returnType, $value)
            +    {
            +        $this->returnType = $returnType;
            +        parent::parserTag('return',$value);
            +    }
            +    
            +    /**
            +     * sets up $converted_returnType
            +     * @see parserStringWithInlineTags::Convert(), $converted_returnType
            +     * @param Converter
            +     * @return string converted value of the tag
            +     */
            +    function Convert(&$converter)
            +    {
            +        $my_types = '';
            +        if (strpos($this->returnType,'|'))
            +        {
            +            $types = explode('|',$this->returnType);
            +            foreach($types as $returntype)
            +            {
            +                $a = $converter->getLink($returntype);
            +                if (is_object($a) && phpDocumentor_get_class($a) == 'classlink')
            +                {
            +                    if (!empty($my_types)) $my_types .= '|';
            +                    $my_types .= $converter->returnSee($a,$converter->type_adjust($returntype));
            +                } else
            +                {
            +                    if (!empty($my_types)) $my_types .= '|';
            +                    $my_types .= $converter->type_adjust($returntype);
            +                }
            +            }
            +            $this->converted_returnType = $my_types;
            +        } else
            +        {
            +            $a = $converter->getLink($this->returnType);
            +            if (is_object($a) && phpDocumentor_get_class($a) == 'classlink')
            +            {
            +                $this->converted_returnType = $converter->returnSee($a,$converter->type_adjust($this->returnType));
            +            } else
            +            {
            +                $this->converted_returnType = $converter->type_adjust($this->returnType);
            +            }
            +        }
            +        return parserTag::Convert($converter);
            +    }
            +}
            +
            +/**
            + * represents "@var"
            + * @tutorial tags.var.pkg
            + * @package phpDocumentor
            + * @subpackage DocBlockTags
            + * @author Greg Beaver 
            + * @since 1.0rc1
            + * @version $Id: DocBlockTags.inc,v 1.1 2005/10/17 18:36:55 jeichorn Exp $
            + */
            +class parserVarTag extends parserReturnTag
            +{
            +    /**
            +     * always 'var'
            +     * @var string
            +     */
            +    var $keyword = 'var';
            +    /**
            +     * the type a var has
            +     * @var string
            +     */
            +    var $returnType = 'mixed';
            +}
            +
            +/**
            + * Represents "@param"
            + * @tutorial tags.param.pkg
            + * @package phpDocumentor
            + * @subpackage DocBlockTags
            + */
            +class parserParamTag extends parserVarTag
            +{
            +    /**
            +     * always 'param'
            +     * @var string
            +     */
            +    var $keyword = 'param';
            +}
            +
            +/**
            + * Represents "@staticvar"
            + * @tutorial tags.staticvar.pkg
            + * @package phpDocumentor
            + * @subpackage DocBlockTags
            + */
            +class parserStaticvarTag extends parserParamTag
            +{
            +    /**
            +     * always 'staticvar'
            +     * @var string
            +     */
            +    var $keyword = 'staticvar';
            +}
            +
            +/**
            + * represents "@link"
            + * @tutorial tags.link.pkg
            + * @package phpDocumentor
            + * @subpackage DocBlockTags
            + * @author Greg Beaver 
            + * @since 1.0rc1
            + * @version $Id: DocBlockTags.inc,v 1.1 2005/10/17 18:36:55 jeichorn Exp $
            + */
            +class parserLinkTag extends parserTag
            +{
            +    /**
            +     * always 'link'
            +     * @var string
            +     */
            +    var $keyword = 'link';
            +    
            +    /**
            +     * URL to link to
            +     * @param string $link
            +     */
            +    function parserLinkTag($link)
            +    {
            +        $start = $val = $link->getString();
            +        if (strpos($val,' '))
            +        {
            +            $start = array_shift($val = explode(' ',$val));
            +            $val = join($val, ' ');
            +        }
            +        $a = new parserLinkInlineTag($start,$val);
            +        $b = new parserStringWithInlineTags;
            +        $b->add($a);
            +        $this->value = $b;
            +    }
            +}
            +
            +/**
            + * represents "@see"
            + * @tutorial tags.see.pkg
            + * @package phpDocumentor
            + * @subpackage DocBlockTags
            + * @author Greg Beaver 
            + * @since 1.0rc1
            + * @version $Id: DocBlockTags.inc,v 1.1 2005/10/17 18:36:55 jeichorn Exp $
            + */
            +class parserSeeTag extends parserLinkTag
            +{
            +    /**
            +     * always 'see'
            +     * @var string
            +     */
            +    var $keyword = 'see';
            +    
            +    /**
            +     * @param string element to link to
            +     */
            +    function parserSeeTag($name)
            +    {
            +        parserTag::parserTag($this->keyword,$name,true);
            +    }
            +
            +    /**
            +     * @param Converter
            +     * @see parserStringWithInlineTags::Convert()
            +     */
            +    function Convert(&$converter)
            +    {
            +        if ($this->value->hasInlineTag())
            +        {
            +            addErrorDie(PDERROR_INLINETAG_IN_SEE);
            +        }
            +        $a = $converter->getLink(trim($this->value->Convert($converter)));
            +        if (is_string($a))
            +        {
            +            // feature 564991
            +            if (strpos($a,'://'))
            +            {
            +                // php function
            +                return $converter->returnLink($a,str_replace('PHP_MANUAL#','',$this->value->Convert($converter)));
            +            }
            +            return $a;
            +        }
            +        if (is_object($a)) return $converter->returnSee($a);
            +        // getLink parsed a comma-delimited list of linked thingies, add the commas back in
            +        if (is_array($a))
            +        {
            +            $b = '';
            +            foreach($a as $i => $bub)
            +            {
            +                if (!empty($b)) $b .= ', ';
            +                if (is_string($a[$i])) $b .= $a[$i];
            +                if (is_object($a[$i])) $b .= $converter->returnSee($a[$i]);
            +            }
            +            return $b;
            +        }
            +        return false;
            +    }
            +}
            +
            +/**
            + * represents "@license"
            + *
            + * Link to a license, instead of including lines and lines of license information
            + * in every file
            + * @tutorial tags.license.pkg
            + * @package phpDocumentor
            + * @subpackage DocBlockTags
            + */
            +class parserLicenseTag extends parserLinkTag
            +{
            +    /**
            +     * always 'license'
            +     * @var string
            +     */
            +    var $keyword = 'license';
            +    
            +    /**
            +     * URL to link to
            +     * @param string $link
            +     */
            +    function parserLicenseTag($name, $link)
            +    {
            +        $a = explode(' ',$link->getString());
            +        $url = array_shift($a);
            +        $license = join($a,' ');
            +        if (empty($license)) $license = $url;
            +        $a = new parserLinkInlineTag($url, $license);
            +        $b = new parserStringWithInlineTags;
            +        $b->add($a);
            +        $this->value = $b;
            +    }
            +}
            +
            +/**
            + * represents "@uses"
            + *
            + * This is exactly like @see except that the element used has a @useby link to this element added to its docblock
            + * @package phpDocumentor
            + * @subpackage DocBlockTags
            + * @tutorial tags.uses.pkg
            + * @since 1.2
            + */
            +class parserUsesTag extends parserSeeTag
            +{
            +    /**
            +     * Always "uses"
            +     * @var string
            +     */
            +    var $keyword = 'uses';
            +    /** @access private */
            +    var $_description;
            +    
            +    /**
            +     * @param string element to link to
            +     * @param parserStringWithInlineTags description of how the element is used
            +     */
            +    function parserUsesTag($seeel, $description)
            +    {
            +        parent::parserSeeTag($seeel);
            +        $this->_description = $description;
            +    }
            +    
            +    /**
            +     * Return a link to documentation for other element, and description of how
            +     * it is used
            +     *
            +     * Works exactly like {@link parent::Convert()} except that it also includes
            +     * a description of how the element used is used.
            +     * @return string
            +     * @param Converter
            +     */
            +    function Convert(&$c)
            +    {
            +        $val = $this->value;
            +        $see = parent::Convert($c);
            +        $this->value = $this->_description;
            +		  $desc_val = parserTag::Convert($c);
            +        if (!empty($desc_val)) {
            +           $see .= ' - '.$desc_val;
            +        }
            +        $this->value = $val;
            +        return $see;
            +    }
            +    
            +    /**
            +     * Get the text of the link to the element that is being used
            +     * @return string
            +     * @access private
            +     */
            +    function getSeeElement()
            +    {
            +        return $this->value->getString();
            +    }
            +    
            +    /**
            +     * Get the description of how the element used is being used.
            +     * @return parserStringWithInlineTags
            +     */
            +    function getDescription()
            +    {
            +        return $this->_description;
            +    }
            +}
            +
            +/**
            + * This is a virtual tag, it is created by @uses to cross-reference the used element
            + *
            + * This is exactly like @uses.
            + * @package phpDocumentor
            + * @subpackage DocBlockTags
            + * @since 1.2
            + */
            +class parserUsedByTag extends parserUsesTag
            +{
            +    /**
            +     * Always "usedby"
            +     * @var string
            +     */
            +    var $keyword = 'usedby';
            +    /** @access private */
            +    var $_link;
            +    
            +    /**
            +     * @param abstractLink link of element that uses this element
            +     * @param string description of how the element is used
            +     */
            +    function parserUsedByTag($link, $description)
            +    {
            +        $this->value = $description;
            +        $this->_link = $link;
            +    }
            +    
            +    /**
            +     * @return string
            +     * @param Converter
            +     */
            +    function Convert(&$c)
            +    {
            +        $see = $c->returnSee($this->_link);
            +		  $desc_val = parserTag::Convert($c);
            +        if (!empty($desc_val)) {
            +           $see .= ' - '.$desc_val;
            +        }
            +        return $see;
            +    }
            +}
            +
            +/**
            + * represents "@tutorial"
            + *
            + * This is exactly like @see except that it only links to tutorials
            + * @tutorial phpDocumentor/tutorials.pkg
            + * @tutorial tags.tutorial.pkg
            + * @package phpDocumentor
            + * @subpackage DocBlockTags
            + * @since 1.2
            + */
            +class parserTutorialTag extends parserSeeTag
            +{
            +    /**
            +     * Always "tutorial"
            +     * @var string
            +     */
            +    var $keyword = 'tutorial';
            +    /**
            +     * @param Converter
            +     * @see parserStringWithInlineTags::Convert()
            +     */
            +    function Convert(&$converter)
            +    {
            +        $a = $converter->getTutorialLink(trim($this->value->Convert($converter)));
            +        if (is_string($a))
            +        {
            +            return $a;
            +        }
            +        if (is_object($a)) return $converter->returnSee($a);
            +        // getLink parsed a comma-delimited list of linked thingies, add the commas back in
            +        if (is_array($a))
            +        {
            +            $b = '';
            +            foreach($a as $i => $bub)
            +            {
            +                if (!empty($b)) $b .= ', ';
            +                if (is_string($a[$i])) $b .= $a[$i];
            +                if (is_object($a[$i])) $b .= $converter->returnSee($a[$i]);
            +            }
            +            return $b;
            +        }
            +        return false;
            +    }
            +}
            +
            +/**
            + * represents "@filesource"
            + * 
            + * Use this to create a link to a highlighted phpxref-style source file listing
            + * @package phpDocumentor
            + * @subpackage DocBlockTags
            + * @tutorial tags.filesource.pkg
            + */
            +class parserFileSourceTag extends parserTag
            +{
            +    /**
            +     * Always "filesource"
            +     * @var string
            +     */
            +    var $keyword = 'filesource';
            +    /** @var array */
            +    var $source;
            +    /** @var string */
            +    var $path;
            +    /**
            +     * Flag variable, controls double writes of file for each converter
            +     * @access private
            +     * @var array
            +     */
            +    var $_converted = array();
            +    /**
            +     * Set {@link $source} to $value, and set up path
            +     * @param string
            +     * @param array output from {@link phpDocumentorTWordParser::getFileSource()}
            +     */
            +    function parserFileSourceTag($filepath, $value)
            +    {
            +        parent::parserTag($this->keyword, '');
            +        $this->path = $filepath;
            +        $this->source = $value;
            +    }
            +
            +    /**
            +     * Return a link to the highlighted source and generate the source
            +     * @uses ConvertSource() generate source code and write it out
            +     * @return string output from {@link getSourceLink()}
            +     * @param Converter
            +     */
            +    function Convert(&$c)
            +    {
            +        if (!isset($this->_converted[$c->name]))
            +        {
            +            $this->ConvertSource($c);
            +            $this->_converted[$c->name] = true;
            +        }
            +        return $this->getSourceLink($c);
            +    }
            +
            +    /**
            +     * @param Converter
            +     * @uses phpDocumentor_HighlightParser highlights source code
            +     * @uses writeSource()
            +     */
            +    function ConvertSource(&$c)
            +    {
            +        $this->writeSource($c, $c->ProgramExample($this->source, true, false, false, false, $this->path));
            +        return;
            +        $parser = new phpDocumentor_HighlightParser;
            +        $return = '';
            +        $return = $parser->parse($this->source,$c, false, false, false, $this->path);
            +        $this->writeSource($c, $return);
            +    }
            +
            +    /**
            +     * @param Converter
            +     * @param string highlighted source code
            +     * @uses Converter::writeSource() export highlighted file source
            +     */
            +    function writeSource(&$c, $source)
            +    {
            +        $c->writeSource($this->path, $source);
            +    }
            +
            +    /**
            +     * @uses Converter::getSourceLink()
            +     * @param Converter
            +     * @return output from getSourceLink()
            +     */
            +    function getSourceLink(&$c)
            +    {
            +        return $c->getSourceLink($this->path);
            +    }
            +}
            +
            +/**
            + * represents "@example"
            + * 
            + * The example tag 
            + * @package phpDocumentor
            + * @subpackage DocBlockTags
            + * @tutorial tags.example.pkg
            + */
            +class parserExampleTag extends parserFileSourceTag
            +{
            +    /**
            +     * always "example"
            +     * @var string
            +     */
            +    var $keyword = 'example';
            +    /**
            +     * Reads and parses the example file indicated
            +     *
            +     * The example tag takes one parameter: the full path to a php file that
            +     * should be parsed and included as an example.
            +     * @uses phpDocumentorTWordParser::getFileSource() uses to parse an example
            +     *       and retrieve all tokens by line number
            +     * @param parserStringWithInlineTags
            +     * @param string path of file containing this @example tag
            +     */
            +    function parserExampleTag($value, $current_path)
            +    {
            +        global $_phpDocumentor_setting;
            +        parent::parserTag('example', $value);
            +        $path = false;
            +        // code thanks to Sam Blum, modified by Greg Beaver
            +        $tagValue = $value->getString();
            +        $path = $isAbsPath = $pathOnly = $fileName = $fileExt = $original_path  = $title = FALSE;
            +        do
            +        {
            +            // make sure the format is stuff.ext description
            +            if (!preg_match('`(.*)\.(\w*)\s(.*)`', $tagValue, $match))
            +            {
            +                // or format is stuff.ext
            +                if (!preg_match('`(.*)\.(\w*)\s*$`', $tagValue, $match))
            +                {
            +                    // Murphy: Some funny path was given
            +                    $original_path = $tagValue; // used for error output
            +                    break; // try-block
            +                }
            +            }
            +            if (strlen($match[1]) === 0)
            +            {
            +                // Murphy: Some funny path was given
            +                $original_path = $tagValue; // used for error output
            +                break; // try-block
            +            }
            +            $fileExt = $match[2];
            +            $title = 'example';
            +            if (isset($match[3]))
            +            {
            +                $title = trim($match[3]);
            +            }
            +            $pathTmp = str_replace('\\', '/', $match[1]); // Replace windows '\' the path.
            +
            +            // Is there a path and a file or is it just a file?
            +            if (strpos($pathTmp,'/') === false)
            +            {
            +                // No path part
            +                $pathOnly = '';
            +                $fileName = $pathTmp .'.'. $fileExt;
            +            } else
            +            {
            +                $splitPos = strrpos($pathTmp,'/'); // split the path on the last directory, find the filename
            +                $pathOnly = substr($match[1], 0, $splitPos+1);
            +                $fileName = substr($match[1], $splitPos+1) .'.'. $fileExt;
            +                // Is the path absolute? (i.e. does it start like an absolute path?)
            +                if (('/' === $pathTmp[0]) || preg_match('`^\w*:`i', $pathTmp))
            +                { // works for both windows 'C:' and URLs like 'http://'
            +                    $isAbsPath = true; // Yes
            +                }
            +            }
            +
            +            $original_path = $pathOnly . $fileName;
            +
            +            // Now look for the file starting with abs. path.
            +            if ($isAbsPath)
            +            {
            +                $tmp = realpath($original_path); // remove any weirdities like /../file.ext
            +                if ($tmp && is_file($tmp))
            +                {
            +                    $path = $tmp;
            +                }
            +                // Alway break if abs. path was detected; even if file was not found.
            +                break; // try-block
            +            }
            +
            +            // Search for the example file some standard places 
            +            // 1) Look if the ini-var examplesdir is set and look there ...
            +            if (isset($_phpDocumentor_setting['examplesdir']))
            +            {
            +                $tmp = realpath($_phpDocumentor_setting['examplesdir'] . PATH_DELIMITER  . $original_path);
            +                if ($tmp && is_file($tmp))
            +                {
            +                    $path = $tmp; // Yo! found it :)
            +                    break; // try-block
            +                }
            +            }
            +
            +            // 2) Then try to look for an 'example/'-dir below the *currently* parsed file ...
            +            if (!empty($current_path))
            +            {
            +                $tmp = realpath(dirname($current_path) . PATH_DELIMITER . 'examples' . PATH_DELIMITER . $fileName);
            +                if ($tmp && is_file($tmp))
            +                {
            +                    $path = $tmp; // Yo! found it :)
            +                    break; // try-block
            +                }
            +            }
            +
            +            // 3) Then try to look for the example file below the subdir PHPDOCUMENTOR_BASE/examples/ ...
            +            if (is_dir(PHPDOCUMENTOR_BASE . PATH_DELIMITER . 'examples'))
            +            {
            +                $tmp = realpath(PHPDOCUMENTOR_BASE . PATH_DELIMITER . 'examples' . PATH_DELIMITER . $original_path);
            +                if ($tmp && is_file($tmp))
            +                {
            +                    $path = $tmp; // Yo! found it :)
            +                    break; // try-block
            +                }
            +            }
            +
            +            $tmp = realpath(PHPDOCUMENTOR_BASE . PATH_DELIMITER . $original_path);
            +            if ($tmp && is_file($tmp))
            +            {
            +                $path = $tmp; // Yo! found it :)
            +                break; // try-block
            +            }
            +            // If we reach this point, nothing was found and $path is false.
            +        } while (false);
            +
            +        if (!$path)
            +        {
            +            addWarning(PDERROR_EXAMPLE_NOT_FOUND, $original_path);
            +            $this->_title = 'example not found';
            +            $this->path = false;
            +        } else
            +        {
            +            $this->_title = ($title) ? $title : 'example';
            +            // make a unique html-filename but avoid it to get too long.
            +            $uniqueFileName = str_replace(array(':', DIRECTORY_SEPARATOR,'/'), array('_', '_', '_'), $path);
            +            $uniqueFileName = substr($uniqueFileName,-50) . '_' . md5($path);
            +            $this->path = $uniqueFileName;
            +            
            +            $f = @fopen($path,'r');
            +            if ($f)
            +            {
            +                $example = fread($f,filesize($path));
            +                if (tokenizer_ext)
            +                {
            +                    $obj = new phpDocumentorTWordParser;
            +                    $obj->setup($example);
            +                    $this->source = $obj->getFileSource();
            +                    unset($obj);
            +                } else
            +                {
            +                    $this->source = $example;
            +                }
            +            }
            +        }
            +    }
            +    
            +    /**
            +     * @param Converter
            +     * @uses phpDocumentor_HighlightParser highlights source code
            +     * @uses writeSource()
            +     */
            +    function ConvertSource(&$c)
            +    {
            +        $this->writeSource($c, $c->ProgramExample($this->source, true));
            +        return;
            +        $parser = new phpDocumentor_HighlightParser;
            +        $return = '';
            +        $return = $parser->parse($this->source,$c);
            +        $this->writeSource($c, $return);
            +    }
            +
            +    /**
            +     * @param Converter $c
            +     * @param string parsed example source
            +     * @uses Converter::writeExample() writes final example out
            +     * @access private
            +     */
            +    function writeSource(&$c, $source)
            +    {
            +        if ($this->path)
            +        $c->writeExample($this->_title, $this->path, $source);
            +    }
            +
            +    /**
            +     * Retrieve a converter-specific link to the example
            +     *
            +     * @param Converter
            +     * @uses Converter::getExampleLink() retrieve the link to the example
            +     */
            +    function getSourceLink(&$c)
            +    {
            +        if (!$this->path) return $this->_title;
            +        return $c->getExampleLink($this->path, $this->_title);
            +    }
            +}
            +
            +?>
            diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Errors.inc b/buildscripts/PhpDocumentor/phpDocumentor/Errors.inc
            new file mode 100644
            index 00000000..99bada26
            --- /dev/null
            +++ b/buildscripts/PhpDocumentor/phpDocumentor/Errors.inc
            @@ -0,0 +1,793 @@
            +
            + * @version $Id: Errors.inc,v 1.1 2005/10/17 18:36:55 jeichorn Exp $
            + */
            +/**
            + * warning triggered when inheritance could be from more than one class
            + */
            +define("PDERROR_MULTIPLE_PARENT",1);
            +/**
            + * warning triggered when parent class doesn't exist
            + */
            +define("PDERROR_PARENT_NOT_FOUND",2);
            +/**
            + * warning triggered when an {@inline tag} is not terminated (no } before the * / ending the comment)
            + */
            +define("PDERROR_UNTERMINATED_INLINE_TAG",3);
            +/**
            + * warning triggered when inheritance could be from more than one class
            + */
            +define("PDERROR_CLASS_EXISTS",4);
            +/**
            + * warning triggered when inheritance could be from more than one class
            + */
            +define("PDERROR_INHERITANCE_CONFLICT",5);
            +/**
            + * warning triggered when a converter is passed to {@link phpDocumentor_IntermediateParser::addConverter()} that is not a class
            + */
            +define("PDERROR_CONVERTER_NOT_FOUND",6);
            +/**
            + * warning triggered when a converter is passed to {@link phpDocumentor_IntermediateParser::addConverter()} that is not a class
            + */
            +define("PDERROR_NO_CONVERTERS",7);
            +/**
            + * warning triggered when the arguments to @access are neither public nor private
            + */
            +define("PDERROR_ACCESS_WRONG_PARAM",8);
            +/**
            + * warning triggered when there are multiple @access tags in a docblock
            + */
            +define("PDERROR_MULTIPLE_ACCESS_TAGS",9);
            +/**
            + * warning triggered when there are multiple @return tags in a docblock
            + */
            +define("PDERROR_MULTIPLE_RETURN_TAGS",10);
            +/**
            + * warning triggered when there are multiple @var tags in a docblock
            + */
            +define("PDERROR_MULTIPLE_VAR_TAGS",11);
            +/**
            + * warning triggered when there are multiple @package tags in a docblock
            + */
            +define("PDERROR_MULTIPLE_PACKAGE_TAGS",12);
            +/**
            + * warning triggered when there are multiple @subpackage tags in a docblock
            + */
            +define("PDERROR_MULTIPLE_SUBPACKAGE_TAGS",13);
            +/**
            + * warning triggered when the package or subpackage name is illegal
            + */
            +define("PDERROR_ILLEGAL_PACKAGENAME",14);
            +/**
            + * warning triggered when there a @package tag is used in a function, define, method, var or include
            + */
            +define("PDERROR_OVERRIDDEN_PACKAGE_TAGS",15);
            +/**
            + * warning triggered when there a @subpackage tag is used in a function, define, method, var or include
            + */
            +define("PDERROR_OVERRIDDEN_SUBPACKAGE_TAGS",16);
            +/**
            + * warning triggered when classes in the same package have the same name
            + */
            +define("PDERROR_CLASS_CONFLICT",17);
            +/**
            + * warning triggered when classes in the same package have the same name
            + */
            +define("PDERROR_UNKNOWN_TAG",18);
            +/**
            + * warning triggered when there are multiple @name tags in a docblock
            + */
            +define("PDERROR_MULTIPLE_NAME_TAGS",19);
            +/**
            + * warning triggered when there are multiple @name tags in a docblock
            + */
            +define("PDERROR_PACKAGEOUTPUT_DELETES_PARENT_FILE",20);
            +/**
            + * warning triggered when there are multiple @name tags in a docblock
            + */
            +define("PDERROR_GLOBAL_NOT_FOUND",21);
            +/**
            + * warning triggered when there are multiple @name tags in a docblock
            + */
            +define("PDERROR_MULTIPLE_GLOBAL_TAGS",22);
            +/**
            + * warning triggered when there are multiple @name tags in a docblock
            + */
            +define("PDERROR_MALFORMED_GLOBAL_TAG",23);
            +/**
            + * warning triggered when an @ignore tag is used in a DocBlock preceding a method, variable, include, or global variable
            + */
            +define("PDERROR_IGNORE_TAG_IGNORED",24);
            +/**
            + * warning triggered when a duplicate element is encountered that will be ignored by the documentor
            + */
            +define("PDERROR_ELEMENT_IGNORED",25);
            +/**
            + * warning triggered when an entire page is ignored because of @access private
            + */
            +define("PDERROR_PARSEPRIVATE",26);
            +/**
            + * warning triggered when an entire page is ignored because of @access private
            + */
            +define("PDERROR_UNKNOWN_COMMANDLINE",27);
            +/**
            + * warning triggered when an entire page is ignored because of @access private
            + */
            +define("PDERROR_NEED_WHITESPACE",28);
            +/**
            + * warning triggered when an entire page is ignored because of @access private
            + */
            +define("PDERROR_CLASS_PARENT_NOT_FOUND",29);
            +/**
            + * warning triggered when a getClassByPackage is called and can't find the class
            + */
            +define("PDERROR_CLASS_NOT_IN_PACKAGE",30);
            +/**
            + * warning triggered when a { @source } inline tag is used in a docblock not preceding a function
            + */
            +define("PDERROR_SOURCE_TAG_FUNCTION_NOT_FOUND",31);
            +/**
            + * warning triggered when a docblock template is never turned off with /**#@-* / (no space)
            + */
            +define("PDERROR_DB_TEMPLATE_UNTERMINATED",32);
            +/**
            + * warning triggered when a docblock has an unmatched <ol> or <ul>
            + */
            +define("PDERROR_UNMATCHED_LIST_TAG",33);
            +/**
            + * warning triggered when another tag is nested in <b> - not allowed in phpDocumentor
            + */
            +define("PDERROR_CANT_NEST_IN_B",34);
            +/**
            + * warning triggered when a docbook tag is not properly matched
            + */
            +define("PDERROR_UNMATCHED_TUTORIAL_TAG",35);
            +/**
            + * warning triggered when an inline tag is found inside an xml tag name in a package page
            + */
            +define("PDERROR_CANT_HAVE_INLINE_IN_TAGNAME",36);
            +/**
            + * warning triggered when a tutorial is referenced via @tutorial/{ @tutorial} and is not found
            + */
            +define("PDERROR_TUTORIAL_NOT_FOUND",37);
            +/**
            + * warning triggered when a tutorial lists itself as a child tutorial
            + */
            +define("PDERROR_TUTORIAL_IS_OWN_CHILD",38);
            +/**
            + * warning triggered when a tutorial's child lists the parent tutorial as a child tutorial
            + */
            +define("PDERROR_TUTORIAL_IS_OWN_GRANDPA",39);
            +/**
            + * warning triggered when a tutorial's child in the .ini file doesn't exist in the
            + * package and subpackage of the parent
            + */
            +define("PDERROR_CHILD_TUTORIAL_NOT_FOUND",40);
            +/**
            + * warning triggered when a  tag is used in the PDF
            + * Converter and no funcname is present ()
            + */
            +define("PDERROR_PDFFUNCTION_NO_FUNC",41);
            +/**
            + * warning triggered when a  tag is used in the PDF
            + * Converter and funcname is not a {@link Cezpdf} method
            + */
            +define("PDERROR_PDF_METHOD_DOESNT_EXIST",42);
            +/**
            + * warning triggered when a  tag is used in the PDF
            + * Converter and "tempvar" is not set from the return of a previous pdffunction tag
            + */
            +define("PDERROR_PDF_TEMPVAR_DOESNT_EXIST",43);
            +/**
            + * warning triggered when a subsection's title is asked for, but the subsection is not found
            + */
            +define("PDERROR_TUTORIAL_SUBSECTION_NOT_FOUND",44);
            +/**
            + * warning triggered when a subsection's title is asked for, but the subsection is not found
            + */
            +define("PDERROR_UNTERMINATED_ATTRIB",45);
            +/**
            + * warning triggered when no @package tag is used in a page-level or class-level DocBlock
            + */
            +define("PDERROR_NO_PACKAGE_TAG",46);
            +/**
            + * warning triggered when no @access private tag is used in a global variable/method/var
            + * with _ as first char in name and --pear was specified
            + */
            +define("PDERROR_PRIVATE_ASSUMED",47);
            +/**
            + * warning triggered when an example's path from @example /path/to/example.php
            + * is not found
            + */
            +define("PDERROR_EXAMPLE_NOT_FOUND",48);
            +/**
            + * warning triggered when an example's path from @example /path/to/example.php
            + * is not found
            + */
            +define("PDERROR_NO_CONVERTER_HANDLER",49);
            +/**
            + * warning triggered when an example's path from @example /path/to/example.php
            + * is not found
            + */
            +define("PDERROR_INLINETAG_IN_SEE",50);
            +/**
            + * warning triggered when an id attribute in a tutorial docbook tag is not
            + * an {@}id} inline tag
            + */
            +define("PDERROR_ID_MUST_BE_INLINE",51);
            +/**
            + * warning triggered when an {@}internal}} tag is not closed
            + */
            +define("PDERROR_INTERNAL_NOT_CLOSED",52);
            +/**
            + * warning triggered when an {@}source} tag is found in a short description
            + */
            +define("PDERROR_SOURCE_TAG_IGNORED",53);
            +/**
            + * warning triggered when a child converter doesn't override getFormattedClassTrees()
            + */
            +define("PDERROR_CONVERTER_OVR_GFCT",54);
            +/**
            + * warning triggered when a package is already associated with a category, and
            + * a new association is found
            + */
            +define("PDERROR_PACKAGECAT_SET",55);
            +/**
            + * warning triggered when text in a docblock list is not contained in
            + * an <
          • > opening tag + */ +define("PDERROR_TEXT_OUTSIDE_LI",56); +/** + * warning triggered when a DocBlock html tag is unclosed + */ +define("PDERROR_UNCLOSED_TAG",57); +/** + * warning triggered by @filesource, if PHP < 4.3.0 + */ +define("PDERROR_TAG_NOT_HANDLED",58); +/** + * warning triggered by sourcecode="on", if PHP < 4.3.0 + */ +define("PDERROR_SOURCECODE_IGNORED",59); +/** + * warning triggered by an empty tag + */ +define("PDERROR_MALFORMED_TAG",60); +/** + * warning triggered by more than 1 @category tag + */ +define("PDERROR_MULTIPLE_CATEGORY_TAGS",61); +/** + * warning triggered by {@}inheritdoc} in a non-inheritable situation + */ +define("PDERROR_INHERITDOC_DONT_WORK_HERE",62); +/** + * warning triggered by @example path/to/example with no title + */ +define("PDERROR_EMPTY_EXAMPLE_TITLE",63); +/** + * warning triggered by non-existent template directory + */ +define("PDERROR_TEMPLATEDIR_DOESNT_EXIST",64); +/** + * warning triggered by an unterminated entity in a tutorial + */ +define("PDERROR_UNTERMINATED_ENTITY",65); +/** + * warning triggered by an unterminated entity in a tutorial + */ +define("PDERROR_BEAUTIFYING_FAILED",66); +/** + * warning triggered by a function with no name + * + *
            + * function ($params)
            + * {
            + * }
            + * 
            + * triggers this error + */ +define("PDERROR_FUNCTION_HAS_NONAME",67); +/** + * warning triggered by a page-level docblock preceding a source element + * + * + * + */ +define("PDERROR_DOCBLOCK_CONFLICT", 68); +/** + * warning triggered when a file does not contain a page-level docblock + */ +define("PDERROR_NO_PAGE_LEVELDOCBLOCK", 69); +/** + * warning triggered when the first docblock in a file with a @package tag + * precedes a class. In this case, the class gets the docblock. + */ +define("PDERROR_DOCBLOCK_GOES_CLASS", 70); +/** + * warning triggered in tutorial parsing if there is a missing {@id} inline tag + */ +define("PDERROR_NO_DOCBOOK_ID", 71); +/** + * warning triggered if someone brilliant tries "class X extends X {" + */ +define("PDERROR_CANNOT_EXTEND_SELF", 72); + +/** + * Error messages for phpDocumentor parser warnings + * @global array $GLOBALS['phpDocumentor_warning_descrip'] + * @name $phpDocumentor_warning_descrip + */ +$GLOBALS['phpDocumentor_warning_descrip'] = + array( + PDERROR_MULTIPLE_PARENT => 'Class %s has multiple possible parents, package inheritance aborted', + PDERROR_PARENT_NOT_FOUND => 'Class %s parent %s not found', + PDERROR_INHERITANCE_CONFLICT => 'Class %s in file %s has multiple possible parents named %s. Cannot resolve name conflict,'."\n".' try ignoring a file that contains the conflicting parent class', + PDERROR_UNKNOWN_TAG => 'Unknown tag "@%s" used', + PDERROR_IGNORE_TAG_IGNORED => '@ignore tag used for %s element "%s" will be ignored', + PDERROR_ELEMENT_IGNORED => "\n".'duplicate %s element "%s" in file %s will be ignored.'."\n".'Use an @ignore tag on the original if you want this case to be documented.', + PDERROR_PARSEPRIVATE => "entire page %s ignored because of @access private.\nChoose -pp to enable parsing of private elements", + PDERROR_CLASS_PARENT_NOT_FOUND => "class %s in package %s parent not found in @see parent::%s", + PDERROR_CLASS_NOT_IN_PACKAGE => "class %s was not found in package %s", + PDERROR_DB_TEMPLATE_UNTERMINATED => "docblock template never terminated with /**#@-*/", + PDERROR_PDF_METHOD_DOESNT_EXIST => ' called, but pdf method "%s" doesn\'t exist', + PDERROR_TUTORIAL_NOT_FOUND => "tutorial \"%s\" not found, does it exist?", + PDERROR_CHILD_TUTORIAL_NOT_FOUND => 'child tutorial "%s" listed in %s not found in parent package "%s" subpackage "%s"', + PDERROR_TUTORIAL_SUBSECTION_NOT_FOUND => 'tutorial %s subsection "%s" doesn\'t exist, but its title was asked for', + PDERROR_NO_PACKAGE_TAG => 'no @package tag was used in a DocBlock for %s %s', + PDERROR_PRIVATE_ASSUMED => '%s "%s" is assumed to be @access private because its name starts with _, but has no @access tag', + PDERROR_EXAMPLE_NOT_FOUND => 'example file "%s" does not exist', + PDERROR_SOURCE_TAG_IGNORED => '{@source} can only be used in the long description, not in the short description: "%s"', + PDERROR_PACKAGECAT_SET => 'package %s is already in category %s, will now replace with category %s', + PDERROR_SOURCECODE_IGNORED => 'sourcecode command-line option is ignored for PHP versions < 4.3.0', + PDERROR_INHERITDOC_DONT_WORK_HERE => '{@inheritdoc} can only be used in the docblock of a child class', + PDERROR_EMPTY_EXAMPLE_TITLE => 'Example file found at "%s" has no title, using "%s"', + PDERROR_DOCBLOCK_CONFLICT => 'Page-level DocBlock precedes "%s %s", use another DocBlock to document the source element', + PDERROR_NO_PAGE_LEVELDOCBLOCK => 'File "%s" has no page-level DocBlock, use @package in the first DocBlock to create one', + PDERROR_DOCBLOCK_GOES_CLASS => 'DocBlock would be page-level, but precedes class "%s", use another DocBlock to document the file', + PDERROR_NO_DOCBOOK_ID => 'Tutorial section %s "%s" has no id="{@id subsection}" tag ({@id} for refentry)', + PDERROR_BEAUTIFYING_FAILED => 'Beautifying failed: %s', + ); + + + +//******************************************************** + + + +/** + * Error messages for phpDocumentor parser errors + * @global array $GLOBALS['phpDocumentor_error_descrip'] + * @name $phpDocumentor_error_descrip + */ +$GLOBALS['phpDocumentor_error_descrip'] = + array( + PDERROR_UNTERMINATED_INLINE_TAG => 'Inline tag {@%s} in tag %s is unterminated, "%s"', + PDERROR_CLASS_EXISTS => 'Class %s already exists in package "%s"', + PDERROR_CONVERTER_NOT_FOUND => 'Converter %s specified by --output command-line option is not a class', + PDERROR_NO_CONVERTERS => 'No Converters have been specified by --output command-line option', + PDERROR_ACCESS_WRONG_PARAM => '@access was passed neither "public" nor "private." Was passed: "%s"', + PDERROR_MULTIPLE_ACCESS_TAGS => 'DocBlock has multiple @access tags, illegal. ignoring additional tag "@access %s"', + PDERROR_MULTIPLE_RETURN_TAGS => 'DocBlock has multiple @return tags, illegal. ignoring additional tag "@return %s %s"', + PDERROR_MULTIPLE_VAR_TAGS => 'DocBlock has multiple @var tags, illegal. ignoring additional tag "@var %s %s"', + PDERROR_MULTIPLE_PACKAGE_TAGS => 'DocBlock has multiple @package tags, illegal. ignoring additional tag "@package %s"', + PDERROR_MULTIPLE_SUBPACKAGE_TAGS => 'DocBlock has multiple @subpackage tags, illegal. ignoring additional tag "@subpackage %s"', + PDERROR_ILLEGAL_PACKAGENAME => '@%s tag has illegal %s name "%s"', + PDERROR_OVERRIDDEN_PACKAGE_TAGS => '%s %s\'s DocBlock has @package tag, illegal. ignoring tag "@package %s"', + PDERROR_OVERRIDDEN_SUBPACKAGE_TAGS => '"%s" %s\'s DocBlock has @subpackage tags, illegal. ignoring tag "@subpackage %s"', + PDERROR_CLASS_CONFLICT => 'class "%s" has multiple declarations in package %s, in file %s and file %s, documentation will have output errors!', + PDERROR_MULTIPLE_NAME_TAGS => 'DocBlock has multiple @name tags, illegal. ignoring additional tag "@name %s"', + PDERROR_PACKAGEOUTPUT_DELETES_PARENT_FILE => '-po (packageoutput) option deletes parent file "%s" containing class "%s."'."\n".' Try using --defaultpackagename (-dn) %s to include the parent file in the same package as the class', + PDERROR_GLOBAL_NOT_FOUND => 'global variable %s specified in @global tag was never found', + PDERROR_MULTIPLE_GLOBAL_TAGS => '@global define tag already used for global variable "%s", ignoring @global %s', + PDERROR_MALFORMED_GLOBAL_TAG => 'incorrect @global syntax. Should be @global vartype $varname or @global vartype description', + PDERROR_UNKNOWN_COMMANDLINE => 'Unknown command-line option "%s" encountered, use phpdoc -h for help', + PDERROR_NEED_WHITESPACE => 'phpDocumentor programmer error - wordparser whitespace set to false in handleDocBlock, notify developers. You should never see this error', + PDERROR_SOURCE_TAG_FUNCTION_NOT_FOUND => '{@source} tag used in a docblock that isn\'t preceding a function', + PDERROR_UNMATCHED_LIST_TAG => 'unmatched ol or ul tag in DocBlock, parsing will be incorrect', + PDERROR_CANT_NEST_IN_B => 'Can\'t nest a code, pre, ul, or ol tag in a b tag in phpDocumentor DocBlock (%s tag nested)', + PDERROR_UNMATCHED_TUTORIAL_TAG => 'While parsing extended documentation, "%s" tag was matched with "%s" endtag, missing endtag'."\ntag contents:\"%s\"", + PDERROR_CANT_HAVE_INLINE_IN_TAGNAME => 'Can\'t have an inline tag inside a package page XML tag!', + PDERROR_TUTORIAL_IS_OWN_CHILD => 'Tutorial %s lists itself as its own child in %s, illegal', + PDERROR_TUTORIAL_IS_OWN_GRANDPA => 'Tutorial %s\'s child %s lists %s as its child in %s, illegal', + PDERROR_PDFFUNCTION_NO_FUNC => 'Invalid pdffunction syntax: "", should be ""', + PDERROR_PDF_TEMPVAR_DOESNT_EXIST => ' called but temporary variable "%s" doesn\'t exist', + PDERROR_UNTERMINATED_ATTRIB => 'Tutorial tag %s attribute %s is unterminated, current value "%s"', + PDERROR_NO_CONVERTER_HANDLER => 'Handler for element of type "%s" called, but %s is not a method of %s', + PDERROR_INLINETAG_IN_SEE => 'Inline tags are not allowed in a @see tag', + PDERROR_ID_MUST_BE_INLINE => '<%s id="%s"> must be <%s id="{@id %s}">', + PDERROR_INTERNAL_NOT_CLOSED => '{@internal was never terminated with }}', + PDERROR_CONVERTER_OVR_GFCT => 'Converter "%s" must override getFormattedClassTrees() but doesn\'t', + PDERROR_TEXT_OUTSIDE_LI => 'Text cannot be outside of li tag in a DocBlock list, parsing will be incorrect', + PDERROR_UNCLOSED_TAG => 'Unclosed %s tag in DocBlock, parsing will be incorrect', + PDERROR_TAG_NOT_HANDLED => '"%s" tag is not available in PHP versions less than 4.3.0, tag ignored', + PDERROR_MALFORMED_TAG => '"%s" tag was used without any parameters, illegal', + PDERROR_MULTIPLE_CATEGORY_TAGS => 'package has multiple @category tags, ignoring "@category %s"', + PDERROR_TEMPLATEDIR_DOESNT_EXIST => 'template directory "%s" does not exist', + PDERROR_UNTERMINATED_ENTITY => 'entity &%s is unterminated', + PDERROR_FUNCTION_HAS_NONAME => 'function has no name (PHP error - test your file before parsing!)', + PDERROR_CANNOT_EXTEND_SELF => 'class %s cannot extend itself - TEST YOUR CODE BEFORE PARSING', + ); + +/** + * encapsulates warning information + * @package phpDocumentor + * @subpackage Errors + */ +class RecordWarning +{ + /** + * name of global variable that descriptors for this warning/error is kept + * @var string + */ + var $type = 'phpDocumentor_warning_descrip'; + /** + * file this error occurred in + * @var string + */ + var $file = false; + /** + * line number of the file this error occurred in + * @var integer + */ + var $linenum; + /** + * error string + * @var string + */ + var $data; + /** + * error number + * @see Errors.inc + * @var string + */ + var $num; + /** + * @param string $file filename this error occurred in ({@link $file}) + * @param integer $linenum line number this error occurred on ({@link $linenum}) + * @param integer $num Error number defined in {@link Errors.inc} + * @param string $data... variable number of strings, up to 4, to sprintf based on the error number + */ + function RecordWarning($file,$linenum,$num) + { + $this->file = $file; + $this->linenum = $linenum; + $a = array('','','',''); + if (func_num_args()>3) + { + for($i=3;$inum = $num; + $this->data = sprintf($GLOBALS[$this->type][$this->num],$a[0],$a[1],$a[2],$a[3]); + $this->output(); + } + + /** + * prints the warning + */ + function output($string = false) + { + if ($string) + { + if ($this->file) + return "WARNING in $this->file on line $this->linenum: $this->data\n"; + else + return "WARNING: $this->data\n"; + } + if ($this->file) + phpDocumentor_out("WARNING in $this->file on line $this->linenum: $this->data\n"); + else + phpDocumentor_out("WARNING: $this->data\n"); + flush(); + } +} + +/** + * encapsulates error information + * @package phpDocumentor + * @subpackage Errors + */ +class RecordError extends RecordWarning +{ + /** + * name of global variable that descriptors for this warning/error is kept + * @var string + */ + var $type = 'phpDocumentor_error_descrip'; + + /** + * prints the error + */ + function output($string = false) + { + if ($string) + { + if ($this->file) + return "\n\tERROR in $this->file on line $this->linenum: $this->data\n"; + else + return "\n\tERROR: $this->data\n"; + } + if ($this->file) + phpDocumentor_out("\n\tERROR in $this->file on line $this->linenum: $this->data\n"); + else + phpDocumentor_out("\n\tERROR: $this->data\n"); + flush(); + } +} + +/** + * contains all the errors/warnings + * @see $errors, $warnings + * @package phpDocumentor + * @subpackage Errors + */ +class ErrorTracker +{ + /** + * array of {@link RecordError}s + * @var array + */ + var $errors = array(); + /** + * array of {@link RecordWarning}s + * @var array + */ + var $warnings = array(); + /** + * @var string + */ + var $curfile = ''; + /** + * @var integer + */ + var $linenum = 0; + + /** + * index in {@link $errors} of last error triggered + * @var integer|false + */ + var $lasterror = false; + + /** + * index in {@link $warnings} of last warning triggered + * @var integer|false + */ + var $lastwarning = false; + + /** + * This function subscribes to two events in the Parser in order to keep track of line number information and file name. + * @param integer $num parser-passed event (see {@link PHPDOCUMENTOR_EVENT_NEWLINENUM, PHPDOCUMENTOR_EVENT_NEWFILE}) + * @param mixed $data either a line number if $num is PHPDOCUMENTOR_EVENT_NEWLINENUM or a file name if $num is PHPDOCUMENTOR_EVENT_NEWFILE + */ + function handleEvent($num,$data) + { + switch($num) + { + case PHPDOCUMENTOR_EVENT_NEWLINENUM : + $this->linenum = $data; + break; + case PHPDOCUMENTOR_EVENT_NEWFILE : + $this->linenum = 0; + $this->curfile = $data; + break; + // debugging + case 1000000635 : + phpDocumentor_out($this->curfile.' has '.$this->linenum.' lines'."\n"); + flush(); + break; + } + } + + /** + * add a new warning to the {@link $warnings} array + * @param integer $num error number from {@link Errors.inc} + * @param string $data... up to 4 string parameters to sprintf() into the error string for error number $num + */ + function addWarning($num) + { + $a = array('','','',''); + if (func_num_args()>1) + { + for($i=1;$iwarnings[] = new RecordWarning($this->curfile,$this->linenum,$num,$a[0],$a[1],$a[2],$a[3]); + $this->lastwarning = count($this->warnings) - 1; + } + + /** + * add a new error to the {@link $errors} array + * @param integer $num error number from {@link Errors.inc} + * @param string $data... up to 4 string parameters to sprintf() into the error string for error number $num + */ + function addError($num) + { + $a = array('','','',''); + if (func_num_args()>1) + { + for($i=1;$ierrors[] = new RecordError($this->curfile,$this->linenum,$num,$a[0],$a[1],$a[2],$a[3]); + $this->lasterror = count($this->errors) - 1; + } + + /** + * add a new error to the {@link $errors} array and returns the error string + * @param integer $num error number from {@link Errors.inc} + * @param string $data... up to 4 string parameters to sprintf() into the error string for error number $num + */ + function addErrorReturn($num) + { + $a = array('','','',''); + if (func_num_args()>1) + { + for($i=1;$ierrors[] = new RecordError($this->curfile,$this->linenum,$num,$a[0],$a[1],$a[2],$a[3],false); + $this->lasterror = count($this->errors) - 1; + } + + /** + * Get sorted array of all warnings in parsing/conversion + * @return array + */ + function &returnWarnings() + { + usort($this->warnings,array($this,"errorsort")); + return $this->warnings; + } + + /** + * Get sorted array of all non-fatal errors in parsing/conversion + * @return array + */ + function &returnErrors() + { + usort($this->errors,array($this,"errorsort")); + return $this->errors; + } + + /** + * @access private + * @param RecordError|RecordWarning + * @param RecordError|RecordWarning + */ + function errorsort($a, $b) + { + if (!$a->file) return -1; + if (!$b->file) return 1; + if ($a->file == $b->file) + { + if ($a->linenum == $b->linenum) return 0; + if ($a->linenum < $b->linenum) return -1; + return 1; + } + return strnatcasecmp($a->file,$b->file); + } + + /** + * Get the error message of the last error + * @return string + */ + function returnLastError() + { + return $this->errors[$this->lasterror]->output(true); + } + + /** + * Get the warning message of the last warning + * @return string + */ + function returnLastWarning() + { + return $this->warnings[$this->lastwarning]->output(true); + } +} + +/** + * @global ErrorTracker $GLOBALS['phpDocumentor_errors'] + * @name $phpDocumentor_errors + */ +$GLOBALS['phpDocumentor_errors'] = new ErrorTracker; + +/** + * @param integer $num error number from {@link Errors.inc} + * @param string $data... up to 4 string parameters to sprintf() into the error string for error number $num + * @see ErrorTracker::addError() + */ +function addError($num) +{ + global $phpDocumentor_errors; + $a = array('','','',''); + if (func_num_args()>1) + { + for($i=1;$iaddError($num,$a[0],$a[1],$a[2],$a[3]); +} + +/** + * like {@link addError()} but exits parsing + * @param integer $num error number from {@link Errors.inc} + * @param string $data... up to 4 string parameters to sprintf() into the error string for error number $num + * @global ErrorTracker repository for all errors generated by phpDocumentor + * @see ErrorTracker::addError() + */ +function addErrorDie($num) +{ + global $phpDocumentor_errors; + $a = array('','','',''); + if (func_num_args()>1) + { + for($i=1;$iaddErrorReturn($num,$a[0],$a[1],$a[2],$a[3]); + die($phpDocumentor_errors->returnLastError()); +} + +/** + * @param integer $num warning number from {@link Errors.inc} + * @param string $data... up to 4 string parameters to sprintf() into the error string for error number $num + * @global ErrorTracker repository for all errors generated by phpDocumentor + * @see ErrorTracker::addWarning() + */ +function addWarning($num) +{ + global $phpDocumentor_errors; + $a = array('','','',''); + if (func_num_args()>1) + { + for($i=1;$iaddWarning($num,$a[0],$a[1],$a[2],$a[3]); +} +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/EventStack.inc b/buildscripts/PhpDocumentor/phpDocumentor/EventStack.inc new file mode 100644 index 00000000..5e2690e8 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/EventStack.inc @@ -0,0 +1,78 @@ + + * @version $Id: EventStack.inc,v 1.1 2005/10/17 18:36:55 jeichorn Exp $ + * @package phpDocumentor + */ +/** + * An event Stack + * + * @author Joshua Eichorn + * @version $Id: EventStack.inc,v 1.1 2005/10/17 18:36:55 jeichorn Exp $ + * @package phpDocumentor + */ +class EventStack +{ + /** + * The stack + * @var array + */ + var $stack = array(PARSER_EVENT_NOEVENTS); + + /** + * The number of events in the stack + * @var integer + */ + var $num = 0; + + /** + * Push an event onto the stack + * + * @param int $event All events must be constants + */ + function pushEvent($event) + { + $this->num = array_push($this->stack,$event) - 1; + } + + /** + * Pop an event from the stack + * + * @return int An event + */ + function popEvent() + { + $this->num--; + return array_pop($this->stack); + } + + /** + * Get the current event + * + * @return int An event + */ + function getEvent() + { + return $this->stack[$this->num]; + } +} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/HighlightParser.inc b/buildscripts/PhpDocumentor/phpDocumentor/HighlightParser.inc new file mode 100644 index 00000000..f2a26ee9 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/HighlightParser.inc @@ -0,0 +1,2354 @@ +_parser = &$parser; + $this->data = &$input; + $this->_all = $input; + $this->_sourceline = 0; + $this->pos = 0; + $this->linenum = 0; + } + + /** + * debugging function + * @access private + */ + function printState() + { + $linenum = $this->linenum; + $pos = $this->pos; + if (!isset($this->_all[$this->linenum][$this->pos])) + { + $linenum++; + $pos = 0; + } + $details = ''; + $token = $this->_all[$linenum][$pos]; + if (is_array($token)) + { + $details = token_name($token[0]); + $token = htmlspecialchars($token[1]); + } else $token = htmlspecialchars($token); + debug('Next Token '.$this->linenum.'-'.$this->pos.':'.$details); + var_dump($token); + } + + /** + * Retrieve the position of the next token that will be parsed + * in the internal token array + * @return array format: array(line number, position) + */ + function nextToken() + { + $linenum = $this->linenum; + $pos = $this->pos; + if (!isset($this->_all[$this->linenum][$this->pos])) + { + $linenum++; + $pos = 0; + } + if (!isset($this->_all[$linenum][$pos])) return false; + return array($linenum, $pos); + } + + /** + * Retrieve the next token + * @return array|string either array(PHP token constant, token) or string + * non-specific separator + */ + function getWord() + { + if (!isset($this->_all[$this->linenum][$this->pos])) + { + $this->linenum++; + $this->pos = 0; + if (!isset($this->_all[$this->linenum])) return false; + $this->_parser->newLineNum(); + return $this->getWord(); + } + $word = $this->_all[$this->linenum][$this->pos++]; + return str_replace("\t",' ',$word); + } + + /** + * back the word parser to the previous token as defined by $last_token + * @param array|string token, or output from {@link nextToken()} + * @param boolean if true, backupPos interprets $last_token to be the + * position in the internal token array of the last token + */ + function backupPos($last_token, $is_pos = false) + { + if ($is_pos) + { + $this->linenum = $last_token[0]; + $this->pos = $last_token[1]; + return; + } + if ($last_token === false) return; +//fancy_debug('before',$this->linenum,$this->pos,token_name($this->_all[$this->linenum][$this->pos][0]),htmlentities($this->_all[$this->linenum][$this->pos][1]),$this->_all[$this->linenum]); + do + { + $this->pos--; + if ($this->pos < 0) + { + $this->linenum--; + if ($this->linenum < 0) { + var_dump($last_token); + break; + } + $this->pos = count($this->_all[$this->linenum]) - 1; + } + } while (!$this->tokenEquals($last_token,str_replace("\t", ' ', $this->_all[$this->linenum][$this->pos]))); + //fancy_debug('after',$this->linenum,$this->pos,token_name($this->_all[$this->linenum][$this->pos][0]),htmlentities($this->_all[$this->linenum][$this->pos][1])); + } +} + +/** + * Highlights source code using {@link parse()} + * @package phpDocumentor + * @subpackage Parsers + */ +class phpDocumentor_HighlightParser extends phpDocumentorTParser +{ + /**#@+ @access private */ + /** + * Highlighted source is built up in this string + * @var string + */ + var $_output; + /** + * contents of the current source code line as it is parsed + * @var string + */ + var $_line; + /** + * Used to retrieve highlighted tokens + * @var Converter a descendant of Converter + */ + var $_converter; + /** + * Path to file being highlighted, if this is from a @filesource tag + * @var false|string full path + */ + var $_filesourcepath; + /** + * @var array + */ + var $eventHandlers = array( + PARSER_EVENT_ARRAY => 'defaultHandler', + PARSER_EVENT_CLASS => 'handleClass', + PARSER_EVENT_COMMENT => 'handleComment', + PARSER_EVENT_DOCBLOCK_TEMPLATE => 'handleDocBlockTemplate', + PARSER_EVENT_END_DOCBLOCK_TEMPLATE => 'handleEndDocBlockTemplate', + PARSER_EVENT_LOGICBLOCK => 'handleLogicBlock', + PARSER_EVENT_METHOD_LOGICBLOCK => 'handleMethodLogicBlock', + PARSER_EVENT_NOEVENTS => 'defaultHandler', + PARSER_EVENT_OUTPHP => 'defaultHandler', + PARSER_EVENT_CLASS_MEMBER => 'handleClassMember', + PARSER_EVENT_DEFINE => 'defaultHandler', + PARSER_EVENT_DEFINE_PARAMS => 'defaultHandler', + PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS => 'defaultHandler', + PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS => 'defaultHandler', + PARSER_EVENT_DOCBLOCK => 'handleDocBlock', + PARSER_EVENT_TAGS => 'handleTags', + PARSER_EVENT_DESC => 'handleDesc', + PARSER_EVENT_DOCKEYWORD => 'handleTag', + PARSER_EVENT_DOCKEYWORD_EMAIL => 'handleDockeywordEmail', + PARSER_EVENT_EOFQUOTE => 'handleQuote', + PARSER_EVENT_FUNCTION => 'handleFunction', + PARSER_EVENT_METHOD => 'handleMethod', + PARSER_EVENT_FUNCTION_PARAMS => 'handleFunctionParams', + PARSER_EVENT_FUNC_GLOBAL => 'handleFuncGlobal', + PARSER_EVENT_INLINE_DOCKEYWORD => 'handleInlineDockeyword', + PARSER_EVENT_INCLUDE => 'defaultHandler', + PARSER_EVENT_INCLUDE_PARAMS => 'defaultHandler', + PARSER_EVENT_QUOTE => 'handleQuote', + PARSER_EVENT_QUOTE_VAR => 'handleQuoteVar', + PARSER_EVENT_PHPCODE => 'handlePhpCode', + PARSER_EVENT_SINGLEQUOTE => 'handleSingleQuote', + PARSER_EVENT_STATIC_VAR => 'defaultHandler', + PARSER_EVENT_STATIC_VAR_VALUE => 'defaultHandler', + PARSER_EVENT_VAR => 'handleVar', + ); + + /** + * event handlers for @tags + * @tutorial tags.pkg + */ + var $tagHandlers = array( + '*' => 'defaultTagHandler', + 'abstract' => 'coreTagHandler', + 'access' => 'coreTagHandler', + 'author' => 'coreTagHandler', + 'category' => 'coreTagHandler', + 'copyright' => 'coreTagHandler', + 'deprecated' => 'coreTagHandler', + 'example' => 'coreTagHandler', + 'filesource' => 'coreTagHandler', + 'final' => 'coreTagHandler', + 'global' => 'globalTagHandler', + 'ignore' => 'coreTagHandler', + 'license' => 'coreTagHandler', + 'link' => 'coreTagHandler', + 'name' => 'coreTagHandler', + 'package' => 'coreTagHandler', + 'param' => 'paramTagHandler', + 'parameter' => 'paramTagHandler', + 'see' => 'coreTagHandler', + 'since' => 'coreTagHandler', + 'subpackage' => 'coreTagHandler', + 'internal' => 'coreTagHandler', + 'return' => 'returnTagHandler', + 'static' => 'coreTagHandler', + 'staticvar' => 'staticvarTagHandler', + 'throws' => 'coreTagHandler', + 'todo' => 'coreTagHandler', + 'tutorial' => 'coreTagHandler', + 'uses' => 'coreTagHandler', + 'var' => 'varTagHandler', + 'version' => 'coreTagHandler', + ); + /**#@-*/ + + /** + * @uses Converter::SourceLine() encloses {@link $_line} in a + * converter-specific format + */ + function newLineNum() + { + if ($this->_pf_no_output_yet) return; + $this->_flush_save(); + $this->_line .= $this->_converter->flushHighlightCache(); + $this->_output .= $this->_converter->SourceLine($this->_wp->linenum, $this->_line, $this->_path); + $this->_line = ''; + } + + /** + * Start the parsing at a certain line number + */ + function setLineNum($num) + { + $this->_wp->linenum = $num; + } + + /** + * Parse a new file + * + * The parse() method is a do...while() loop that retrieves tokens one by + * one from the {@link $_event_stack}, and uses the token event array set up + * by the class constructor to call event handlers. + * + * The event handlers each process the tokens passed to them, and use the + * {@link _addoutput()} method to append the processed tokens to the + * {@link $_line} variable. The word parser calls {@link newLineNum()} + * every time a line is reached. + * + * In addition, the event handlers use special linking functions + * {@link _link()} and its cousins (_classlink(), etc.) to create in-code + * hyperlinks to the documentation for source code elements that are in the + * source code. + * + * @uses setupStates() initialize parser state variables + * @uses configWordParser() pass $parse_data to prepare retrieval of tokens + * @param array $parse_data + * @param Converter $converter + * @param boolean $inlinesourceparse whether this data is from an + * inline {@}source} tag + * @param string|false if a string, it is the name of the class whose + * method we are parsing containing a {@}source} tag + * @param false|integer starting line number from {@}source linenum} + * @param false|string full path to file with @filesource tag, if this + * is a @filesource parse + * @staticvar integer used for recursion limiting if a handler for + * an event is not found + * @return bool + */ + function parse (&$parse_data, &$converter, $inlinesourceparse = false, $class = false, $linenum = false, $filesourcepath = false) + { + if (!tokenizer_ext) + { + if (is_array($parse_data)) + { + $parse_data = join($parse_data,''); + } + $parse_data = explode("\n", $parse_data); + $this->_output = ''; + foreach($parse_data as $linenum => $line) + { + if ($linenum > 0) + { + $this->_output .= $converter->SourceLine($linenum, $line, $filesourcepath); + } + } + return $converter->PreserveWhiteSpace($this->_output); + } + static $endrecur = 0; + $this->_converter = &$converter; + $converter->startHighlight(); + $this->_path = $filesourcepath; + $this->setupStates($inlinesourceparse, $class); + + $this->configWordParser($parse_data); + if ($linenum !== false) $this->setLineNum($linenum); + // initialize variables so E_ALL error_reporting doesn't complain + $pevent = 0; + $word = 0; + + do + { + $lpevent = $pevent; + $pevent = $this->_event_stack->getEvent(); + if ($lpevent != $pevent) + { + $this->_last_pevent = $lpevent; + } + + if ($pevent == PARSER_EVENT_CLASS_MEMBER) + { + $this->_wp->setWhitespace(true); + } else + { + $this->_wp->setWhitespace(false); + } + + if (!is_array($word)) $lw = $word; + if (is_array($word) && $word[0] != T_WHITESPACE) $lw = $word; + $dbg_linenum = $this->_wp->linenum; + $dbg_pos = $this->_wp->getPos(); + $word = $this->_wp->getWord(); + if (is_array($word) && $word[0] == T_WHITESPACE && $pevent != PARSER_EVENT_CLASS_MEMBER) + { +// debug("added ".$this->_wp->linenum.'-'.$this->_wp->pos); + $this->_addoutput($word); + continue; + } else $this->_pv_last_word = $lw; + if ($pevent != PARSER_EVENT_DOCBLOCK) + { + $this->_pv_last_next_word = $this->_pv_next_word; + $this->_pv_next_word = $this->_wp->nextToken(); + } + // in wordparser, have to keep track of lines +// $this->publishEvent(PHPDOCUMENTOR_EVENT_NEWLINENUM, $this->_wp->linenum); + if (0)//PHPDOCUMENTOR_DEBUG == true) + { + echo "LAST: "; + if (is_array($this->_pv_last_word)) + { + echo token_name($this->_pv_last_word[0]). ' => |'.htmlspecialchars($this->_pv_last_word[1]); + } else echo "|" . $this->_pv_last_word; + echo "|\n"; + echo "PEVENT: " . $this->getParserEventName($pevent) . "\n"; + echo "LASTPEVENT: " . $this->getParserEventName($this->_last_pevent) . "\n"; +// echo "LINE: ".$this->_line."\n"; +// echo "OUTPUT: ".$this->_output."\n"; + echo $dbg_linenum.'-'.$dbg_pos . ": "; + if (is_array($word)) + { + echo token_name($word[0]).' => |'.htmlspecialchars($word[1]); + } else echo '|'.htmlspecialchars($word); + echo "|\n"; + $this->_wp->printState(); + echo "NEXT TOKEN: "; + $tok1 = $this->_pv_next_word; + $tok = $this->_wp->_all[$tok1[0]][$tok1[1]]; + if (is_array($tok)) + { + echo token_name($tok[0]). ' => '.$tok1[0].'-'.$tok1[1].'|'.htmlspecialchars($tok[1]); + } else echo "|" . $tok; + echo "|\n"; + echo "-------------------\n\n\n"; + flush(); + } + if (isset($this->eventHandlers[$pevent])) + { + $handle = $this->eventHandlers[$pevent]; + $this->$handle($word, $pevent); + } else + { + debug('WARNING: possible error, no handler for event number '.$pevent); + if ($endrecur++ == 25) + { + die("FATAL ERROR, recursion limit reached"); + } + } + } while (!($word === false)); + if (strlen($this->_line)) $this->newLineNum(); + return $this->_output; + } + + /**#@+ + * Event Handlers + * + * All Event Handlers use {@link checkEventPush()} and + * {@link checkEventPop()} to set up the event stack and parser state. + * @access private + * @param string|array token value + * @param integer parser event from {@link Parser.inc} + */ + /** + * Most tokens only need highlighting, and this method handles them + */ + function defaultHandler($word, $pevent) + { + $this->_addoutput($word); + if ($this->checkEventPush($word, $pevent)) return; + $this->checkEventPop($word, $pevent); + } + + /** + * Handles global declarations in a function, like: + * + * + * function foobar() + * { + * global $_phpDocumentor_setting; + * } + * + * @uses _globallink() instead of _addoutput(), to link to global variables + * if they are used in a function + */ + function handleFuncGlobal($word, $pevent) + { + if ($this->checkEventPush($word, $pevent)) return; + $this->_globallink($word); + $this->checkEventPop($word, $pevent); + } + + /** + * Handles strings in quotation marks and heredoc + * + * Special handling is needed for strings that contain variables like: + * + * $a = "$test string" + * + * The tokenizer parses out tokens '"',array(T_VARIABLE,'$test'),' string', + * and '"'. Since it is possible to have $this->classvar in a string, + * we save a variable name just in case the next token is -> to allow linking + * to class members. Otherwise, the string is simply highlighted. + * + * constant strings (with no $variables in them) are passed as a single + * entity, and so will be saved in the last token parsed. This means the + * event handler must tell the word parser to re-retrieve the current token + * so that the correct event handler can process it. + */ + function handleQuote($word, $pevent) + { + if ($this->_pf_inmethod && is_array($word) && $word[0] == T_VARIABLE) $this->_pv_lastvar = $word; + if ($this->checkEventPush($word, $pevent)) + { + $this->_addoutput($word); + return; + } + if ($this->_pf_quote_active && + (($this->_pv_last_word == '"' && $this->_last_pevent != PARSER_EVENT_QUOTE) || + (is_array($this->_pv_last_word) && $this->_pv_last_word[0] == T_END_HEREDOC && + $this->_last_pevent != PARSER_EVENT_EOFQUOTE))) + { + $this->_pf_quote_active = false; + $this->_wp->backupPos($word); + $this->_event_stack->popEvent(); + return; + } + if (!$this->_pf_quote_active && + (($this->_pv_last_word == '"' && $this->_last_pevent != PARSER_EVENT_QUOTE) || + (is_array($this->_pv_last_word) && $this->_pv_last_word[0] == T_END_HEREDOC && + $this->_last_pevent != PARSER_EVENT_EOFQUOTE))) + { + if (is_array($word) && $word[0] == T_VARIABLE) $this->_pv_lastvar = $word; + $this->_pf_quote_active = true; + $this->_save_highlight_state = $this->_converter->getHighlightState(); + $this->_converter->startHighlight(); + $this->_addoutput($word); + $this->checkEventPop($word, $pevent); + return; + } elseif (is_array($this->_pv_last_word) && $this->_pv_last_word[0] == T_CONSTANT_ENCAPSED_STRING) + { +// $this->_pv_quote_data = $this->_pv_last_word[1]; + $this->_event_stack->popEvent(); + $this->_wp->backupPos($word); + return; + } + if ($this->checkEventPop($word, $pevent)) + { + $this->_pf_quote_active = false; + } + $this->_addoutput($word); + } + + /** + * Handles {$variable} within a "quote" + * + * This is a simple handler, for a very complex + * array of legal syntax. It is legal to nest control structures + * inside the {}, and other weird stuff. + */ + function handleQuoteVar($word, $pevent) + { + if ($this->checkEventPop($word, $pevent)) + { + $this->_pf_quote_active = true; + $this->_addoutput($word); + return; + } + if ($this->_pf_inmethod && is_array($word) && $word[0] == T_VARIABLE) $this->_pv_lastvar = $word; + if ($this->checkEventPush($word, $pevent)) + { + $this->_pf_quote_active = false; + if (is_string($word) && ($word == '{' || $word == '"' || $word == "'")) + { + $this->_pf_quote_active = true; + $this->_pv_lastvar = false; + } + } + $this->_addoutput($word); + } + + /** + * Handles define() statements + * + * The only thing this handler cares about is retrieving the name of the + * define variable, and the end of the define statement, so after the name + * is found, it simply makes sure parentheses are matched as in this case: + * + * + * define("test",array("hello",6 => 4, 5 => array('there'))); + * + * + * This handler and the DEFINE_PARAMS_PARENTHESIS handler (which is just + * {@link defaultHandler()} in this version, as nothing fancy is needed) + * work together to ensure proper parenthesis matching. + * + * If the define variable is documented, a link will be created to its + * documentation using the Converter passed. + */ + function handleDefine($word, $pevent) + { + static $token_save; + if (!isset($token_save)) $token_save = array(); + $e = $this->checkEventPush( $word, $pevent); + if ($e && $e != PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS) return; + + if(!isset($this->_pv_define_params_data)) $this->_pv_define_params_data = ''; + + if ($this->checkEventPop($word,$pevent)) + { + unset($token_save); + $this->_addoutput($word); + } + if ($this->_pf_definename_isset) + { + $this->_addoutput($word); + } else + { + if ($word != ",") + { + $token_save[] = $word; + if (is_array($word)) $word = $word[1]; + $this->_pv_define_params_data .= $word; + } else + { + if (substr($this->_pv_define_params_data,0,1) == + substr($this->_pv_define_params_data,strlen($this->_pv_define_params_data) - 1) && + in_array(substr($this->_pv_define_params_data,0,1),array('"',"'"))) + { // remove leading and ending quotation marks if there are only two + $a = substr($this->_pv_define_params_data,0,1); + $b = substr($this->_pv_define_params_data,1,strlen($this->_pv_define_params_data) - 2); + if (strpos($b,$a) === false) + { + $this->_pv_define_params_data = $b; + } + } + $this->_pf_definename_isset = true; + $link = $this->_converter->getLink($this->_pv_define_params_data); + foreach ($token_save as $token) + { + if (is_object($link)) + { + if (is_array($token)) $token = $token[1]; + $this->_addoutput($this->_converter->returnSee($link, $token)); + } else + { + $this->_addoutput($save, $token); + } + } + $this->_pv_define_params_data = ''; + } + } + } + + /** + * Handles normal global code. Special consideration is taken for DocBlocks + * as they need to retrieve the whole DocBlock before doing any output, so + * the parser flag {@link $_pf_no_output_yet} is set to tell + * {@link _addoutput()} not to spit anything out yet. + * @uses _link() make any global code that is a documentable element link + * to the php manual or its documentation + */ + function handlePhpCode($word, $pevent) + { + $test = $this->checkEventPush($word, $pevent); + if ($test == PARSER_EVENT_DOCBLOCK || $test == PARSER_EVENT_COMMENT) + { + $this->_pf_no_output_yet = true; + $this->_pv_saveline = $this->_wp->linenum + 1; + return; + } + if (is_array($word) && $word[0] == T_DOUBLE_COLON) $this->_pf_colon_colon = true; + if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) $this->_pv_last_string = $word; + $this->_link($word); + $this->checkEventPop($word, $pevent); + } + + /** + * Handle the function declaration header + * + * This handler only sees the "function name" portion of the function + * declaration. Handling of the function parameters is by + * {@link handleFunctionParams()}, and the function body is handled by + * {@link handleLogicBlock()} + */ + function handleFunction($word, $pevent) + { + if ($this->checkEventPush($word, $pevent)) + { + $this->_addoutput($word); + return; + } + if ($this->checkEventPop($word, $pevent)) return; + $this->_link($word); + } + + /** + * Handle the method declaration header + * + * This handler only sees the "function name" portion of the method + * declaration. Handling of the method parameters is by + * {@link handleFunctionParams()}, and the method body is handled by + * {@link handleMethodLogicBlock()} + */ + function handleMethod($word, $pevent) + { + if ($this->checkEventPush($word, $pevent)) + { + $this->_addoutput($word); + return; + } + if ($this->checkEventPop($word, $pevent)) { + if ($word == ';') { + $this->_addoutput($word); + } + return; + } + $this->_methodlink($word); + } + + /** + * Handler for the stuff between ( and ) in a function declaration + * + * + * function handles($only,$these,$parameters){...} + * + */ + function handleFunctionParams($word, $pevent) + { + if ($this->checkEventPush($word, $pevent)) + { + $this->_addoutput($word); + return; + } + $this->_addoutput($word); + $this->checkEventPop($word, $pevent); + } + + /** + * Handler for function body. + * + * The function body is checked for php functions, documented constants, + * functions, and indirectly for global statements. It hyperlinks to the + * documentation for detected elements is created. Everything else is + * highlighted normally. + */ + function handleLogicBlock($word, $pevent) + { + if ($this->checkEventPush($word, $pevent)) + { + $this->_addoutput($word); + return; + } + if (is_array($word) && $word[0] == T_DOUBLE_COLON) $this->_pf_colon_colon = true; + if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) $this->_pv_last_string = $word; + $this->_link($word); + if ($this->checkEventPop($word,$pevent)) + { + $e = $this->_event_stack->popEvent(); + $this->_event_stack->pushEvent($e); + if ($e == PARSER_EVENT_FUNCTION) + { + $this->_wp->backupPos($word); + } + } + } + + /** + * Handler for method body. + * + * Like functions, the method body is checked for php functions, documented + * constants, functions, and indirectly for global statements. It also + * checks for "$this->XXXX" where XXXX is a class variable or method, and + * links to the documentation for detected elements is created. Everything + * else is highlighted normally. + */ + function handleMethodLogicBlock($word, $pevent) + { + if (isset($this->_pv_prev_var_type)) + { +// debug('prevtype is set'); + if (!is_array($word)) unset($this->_pv_prev_var_type); + else + { + if ($word[0] != T_WHITESPACE && $word[0] != T_STRING && $word[0] != T_OBJECT_OPERATOR) + { +// fancy_debug('unset',$word); + unset($this->_pv_prev_var_type); + } + } + } + $this->_pf_inmethod = true; + if ($e = $this->checkEventPush($word, $pevent)) + { + $this->_addoutput($word); + if ($e == PARSER_EVENT_CLASS_MEMBER) { + $this->_pf_no_output_yet = true; + } + return; + } + if (is_array($word) && $word[0] == T_DOUBLE_COLON) $this->_pf_colon_colon = true; + if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) $this->_pv_last_string = $word; + if (is_array($word) && $word[0] == T_VARIABLE) $this->_pv_lastvar = $word; + $this->_link($word); + if ($this->checkEventPop($word,$pevent)) + { + $this->_pf_inmethod = false; + $e = $this->_event_stack->popEvent(); + $this->_event_stack->pushEvent($e); + if ($e == PARSER_EVENT_METHOD) + { + $this->_wp->backupPos($word); + } + } + } + + /** + * Handles $obj->classmember in a method body + * + * This handler is responsible for linking to the documentation of a + * class member when it is used directly in a method body. + * + * There are two methods of determining whether to link: + * - $this->member + * - $this->member->submember + * + * The first case is handled by the $_pv_lastvar variable, and the + * second case is handled by the $_pv_prev_var_type variable. $_pv_lastvar + * is always set to the value of the last T_VARIABLE token, if and only if + * no text has occurred between the variable and a T_OBJECT_OPERATOR token + * "->". handleClassMember will only link if the last variable encountered + * was $this. + * + * When $this->variable is encountered, the variable is looked up to see + * if it can be found, and if so, the contents of its @var tag are processed + * to see if the member variable is defined to have 1 and only 1 class. + * If so, the $_pv_prev_var_type variable is set to this classname. When + * submember is processed, the HighlightParser checks to see if + * $_pv_prev_var_type::submember() or $_pv_prev_var_type::$submember exists, + * and if it does, it is linked to. + */ + function handleClassMember($word, $pevent) + { + if (!isset($this->_pv_lastvar) && !isset($this->_pv_prev_var_type)) + { +// fancy_debug('returned from',$word,$this->_pv_prev_var_type); + $this->_pf_no_output_yet = false; + $this->_event_stack->popEvent(); + return $this->defaultHandler($word, $pevent); + } + if (isset($this->_pv_cm_name)) + { + $this->_pf_obj_op = false; + $name = $this->_pv_cm_name; + unset($this->_pv_cm_name); +// debug('unset pvcmname'); + $this->_event_stack->popEvent(); + // control variable for _pv_prev_var_type + $setnow = false; + if ((isset($this->_pv_lastvar) && $this->_pv_lastvar[1] == '$this') + || isset($this->_pv_prev_var_type)) + { + if (is_array($word) && $word[0] == T_WHITESPACE) + { + // preserve value of _pv_prev_var_type + $setnow = true; + $save = $this->_wp->nextToken(); + $temp = $this->_wp->getWord(); + $this->_wp->backupPos($save, true); + } + if ((is_string($word) && $word == '(') || + (isset($temp) && is_string($temp) && $temp == '(')) + { // it's a function + $this->_pf_no_output_yet = false; + $this->_methodlink($name); + unset($this->_pv_prev_var_type); + } else + { // it's a variable +// fancy_debug('name is ',$name); + $this->_pf_no_output_yet = false; + $this->_varlink($name, true); + $templink = $this->_converter->getLink('object '.$this->_pv_class); + $class = false; + if (is_object($templink)) { + $class = $this->_converter->classes->getClass($templink->name, $templink->path); + } + if ($class) + { + $varname = $name; + if (is_array($varname)) $varname = $name[1]; + if ($varname{0} != '$') $varname = '$'.$varname; + $var = $class->getVar($this->_converter, $varname); + + if (is_object($var) && $var->docblock->var) + $type = $var->docblock->var->returnType; + if (isset($type)) + { + if (strpos($type, 'object') === false) + $type = 'object '.$type; + $type = $this->_converter->getLink($type); + if (phpDocumentor_get_class($type) == 'classlink') + { // the variable's type is a class, save it for future -> +// fancy_debug('set prev_var_type!',$type->name); + $setnow = true; + $this->_pv_prev_var_type = $type->name; + } else unset($this->_pv_prev_var_type); + } else unset($this->_pv_prev_var_type); + } else unset($this->_pv_prev_var_type); + } + } else { + $this->_pf_no_output_yet = false; + // this does NewLinenum if necessary + $this->_wp->backupPos($word); + $this->_wp->getWord(); + $this->_addoutput($name); + } + if (!$setnow) + { +// debug('unset prevtype, no setnow'); + unset($this->_pv_prev_var_type); + } + unset($this->_pv_lastvar); + $this->_pf_no_output_yet = false; + // this does NewLinenum if necessary + $this->_wp->backupPos($word); + $this->_wp->getWord(); + if ($word[0] == T_OBJECT_OPERATOR) + $this->_wp->backupPos($word); + else + $this->_addoutput($word); + return; + } + if (!$this->_pf_obj_op && is_array($this->_pv_last_word) && $this->_pv_last_word[0] == T_OBJECT_OPERATOR) + { + if ((isset($this->_pv_lastvar) && $this->_pv_lastvar[1] == '$this') || isset($this->_pv_prev_var_type)) + { + $this->_pf_obj_op = true; + } else + { + $this->_pf_no_output_yet = false; + // this does NewLinenum if necessary + $this->_wp->backupPos($word); + $this->_wp->getWord(); + $this->_addoutput($word); + $this->_event_stack->popEvent(); + } + } + if (is_array($word) && $word == T_WHITESPACE) + { + $this->_pf_no_output_yet = false; + // this does NewLinenum if necessary + $this->_wp->backupPos($word); + $this->_wp->getWord(); + $this->_addoutput($word); + return; + } + if ($this->_pf_obj_op) + { + if (!(is_array($word) && ($word[0] == T_STRING || $word[0] == T_WHITESPACE))) + { + unset($this->_pv_lastvar); +// debug('unset lastvar'); + $this->_event_stack->popEvent(); + $this->_pf_no_output_yet = false; + // this does NewLinenum if necessary + $this->_wp->backupPos($word); + $this->_wp->getWord(); + $this->_addoutput($word); + return; + } + if ($word[0] == T_STRING) + { +// fancy_debug('set pvcmname to',$word); + $this->_pv_cm_name = $word; + } else { + $this->_pf_no_output_yet = false; + // this does NewLinenum if necessary + $this->_wp->backupPos($word); + $this->_wp->getWord(); + $this->_addoutput($word); + } + } + } + + /** + * Handles comments + * + * Comments are almost always single-line tokens, and so will be + * in the last word. This handler checks to see if the current token + * is in fact a comment, and if it isn't, it backs up and returns control + * to the parent event handler with that word. + */ + function handleComment($word, $pevent) + { + $w = $this->_pv_last_word; + // don't perform this check if this is a normal comment. Docblocks + // have the _pf_no_output_yet variable set to true + if ($this->_pf_no_output_yet && + is_array($w) && (in_array($w[0], array(T_COMMENT, T_DOC_COMMENT)) && strpos($w[1],'/**') === 0)) { + $this->_event_stack->popEvent(); + $this->_event_stack->pushEvent(PARSER_EVENT_DOCBLOCK); + return $this->handleDocBlock($word, PARSER_EVENT_DOCBLOCK); + } + if ($this->_pf_no_output_yet) { + $flag = 1; + $this->_pf_no_output_yet = false; + $this->_addoutput($this->_pv_last_word); + } + if (!is_array($word) || !in_array($word[0], array(T_COMMENT, T_DOC_COMMENT)) || + (in_array($word[0], array(T_COMMENT, T_DOC_COMMENT)) && strpos($word[1],'/**') === 0)) + { + $this->_event_stack->popEvent(); + if (strpos($this->_pv_last_word[1], "\n") !== false) + { +// $this->_wp->linenum++; +// $this->newLineNum(); + } + $this->_wp->backupPos($this->_pv_last_word); + $this->_wp->getWord(); +// var_dump($this->_wp->nextToken()); + return; + } elseif (isset($flag)) { + $this->newLineNum(); + } + $this->_addoutput($word); + $this->checkEventPop($word, $pevent); + if (strpos($word[1], '*/') === strlen($word[1]) - 2) { + $this->_event_stack->popEvent(); + } + } + + /** + * Handle class declarations + * + * Handles the initial declaration line: + * + * class X + * + * or + * + * class X extends Y implements I + * + * @uses _classlink() to link to documentation for X and for Y class in + * "class X extends Y" + */ + function handleClass($word, $pevent) + { + $this->_pf_in_class = true; + $a = $this->checkEventPush( $word, $pevent); + + if (!isset($this->_pv_class) && is_array($word) && $word[0] == T_STRING) + { + $this->_pv_class = $this->_converter->class = $word[1]; + $this->_classlink($word); + return; + } + + if (is_array($word) && in_array($word[0], array(T_PRIVATE, T_PROTECTED, T_PUBLIC))) { + $starttok = $this->_wp->nextToken(); + $test = array(T_WHITESPACE); + while ($test && $test[0] == T_WHITESPACE) { + $tok = $this->_wp->nextToken(); + $test = $this->_wp->getWord(); + } // while + + if (is_array($test) && $test[0] == T_VARIABLE) { + $this->_wp->backupPos($tok, true); + return; + } + $this->_wp->backupPos($starttok, true); + } + + if (@in_array($this->_pv_last_word[0], array(T_PRIVATE, T_PROTECTED, T_PUBLIC))) { + if (is_array($word) && $word[0] == T_VARIABLE) { + $this->_wp->backupPos($this->_pv_last_word); + $this->_event_stack->pushEvent(PARSER_EVENT_VAR); + return; + } + } + + if ($this->_pf_extends_found && is_array($word) && $word[0] == T_STRING) + { + $this->_classlink($word); + return; + } + if (is_array($word) && $word[0] == T_EXTENDS) $this->_pf_extends_found = true; + if ($a == PARSER_EVENT_DOCBLOCK) + { + $this->_pf_no_output_yet = true; + $this->_pv_saveline = $this->_wp->linenum + 1; + return; + } + $this->_addoutput($word); + if ($this->checkEventPop($word,$pevent)) + { + $this->_pf_in_class = false; + unset($this->_pv_class); + } + } + + /** + * Handles class variable declaration + * + * + * class X + * { + * var $Y; + * } + * + * @uses _varlink() make a link to $Y documentation in class variable + * declaration "var $Y;" + */ + function handleVar($word, $pevent) + { + if ($this->checkEventPush($word, $pevent)) + { + $this->_addoutput($word); + return; + } + if (is_array($word) && $word[0] == T_VARIABLE) + { + return $this->_varlink($word); + } + $this->_addoutput($word); + $this->checkEventPop($word, $pevent); + } + + /** + * This handler is responsible for highlighting DocBlocks + * + * handleDocBlock determines whether the docblock is normal or a template, + * and gathers all the lines of the docblock together before doing any + * processing + * + * As it is not possible to distinguish any comment token from a docblock + * token, this handler is also called for comments, and will pass control + * to {@link handleComment()} if the comment is not a DocBlock + * @uses commonDocBlock() once all lines of the DocBlock have been retrieved + */ + function handleDocBlock($word, $pevent) + { + if (!($this->_pf_docblock || $this->_pf_docblock_template)) + { + if (strpos($this->_pv_last_word[1],'/**') !== 0) + { // not a docblock + $this->_wp->backupPos($this->_pv_last_word); + $this->_event_stack->popEvent(); + $this->_event_stack->pushEvent(PARSER_EVENT_COMMENT); + $this->_pf_no_output_yet = false; + return; + } else + { + $this->_pf_no_output_yet = true; + $this->_pv_db_lines = array(); + } + } + $last_word = $this->_pv_last_word[1]; + $dtype = '_pv_docblock'; + if ($last_word == '/**#@-*/') + { // stop using docblock template + $this->_pf_no_output_yet = false; + $this->_addDocBlockoutput('closetemplate', $last_word); + if ($this->_pv_next_word !== false) { + $this->_wp->backupPos($this->_pv_next_word,true); + } + $this->_event_stack->popEvent(); + return; + } + if (!($this->_pf_docblock || $this->_pf_docblock_template)) + { + $this->_pv_db_lines = array(); + if (strpos($last_word,'/**#@+') === 0) + { // docblock template definition + $this->_pf_docblock_template = true; + } else + { + $this->_pf_docblock = true; + } + $this->_pv_db_lines[] = $last_word; + if (strpos($last_word,'*/') !== false) + { + $this->commonDocBlock(); + return; + } + $this->_pv_db_lines[] = $word[1]; + if (strpos($word[1],'*/') !== false) + { + $this->commonDocBlock(); + } + } else + { + $this->_pv_db_lines[] = $word[1]; + } + if (($this->_pf_docblock || $this->_pf_docblock_template) && (strpos($word[1],'*/') !== false)) + { + $this->commonDocBlock(); + } + } + /**#@-*/ + /** + * This continuation of handleDocBlock splits DocBlock comments up into + * phpDocumentor tokens. It highlights DocBlock templates in a different + * manner from regular DocBlocks, recognizes inline tags, regular tags, + * and distinguishes between standard core tags and other tags, and + * recognizes parameters to tags like @var. + * + * the type in "@var type description" will be highlighted as a php type, + * and the var in "@param type $var description" will be highlighted as a + * php variable. + * @uses handleDesc() highlight inline tags in the description + * @uses handleTags() highlight all tags + * @access private + */ + function commonDocBlock() + { + $this->_event_stack->popEvent(); + $lines = $this->_pv_db_lines; + $go = count($this->_pv_db_lines); + for($i=0;$i<$go;$i++) + { + if (substr(trim($lines[$i]),0,2) == '*/' || substr(trim($lines[$i]),0,1) != '*' && substr(trim($lines[$i]),0,3) != '/**') + { + $lines[$i] = array($lines[$i],false); + } elseif (substr(trim($lines[$i]),0,3) == '/**') + { + $linesi = array(); + $linesi[1] = substr(trim($lines[$i]),3); // remove leading "/**" + if (empty($linesi[1])) + $linesi[0] = $lines[$i]; + else + $linesi[0] = substr($lines[$i],0,strpos($lines[$i],$linesi[1])); + $lines[$i] = $linesi; + } else + { + $linesi = array(); + $linesi[1] = substr(trim($lines[$i]),1); // remove leading "* " + if (empty($linesi[1])) + $linesi[0] = $lines[$i]; + else + $linesi[0] = substr($lines[$i],0,strpos($lines[$i],$linesi[1])); + $lines[$i] = $linesi; + } + } + for($i = 0;$i_pf_no_output_yet = false; + $save = $this->_wp->linenum; + $this->_wp->linenum = $this->_pv_saveline; + $this->handleDesc($desc); + $this->handleTags($tags); + $this->_pv_db_lines = array(); + $this->_wp->linenum = $save; + if (strpos($this->_pv_last_word[1],'*/') !== false) + { + $this->_wp->backupPos($this->_pv_next_word,true); + } + $this->_pf_docblock = $this->_pf_docblock_template = false; + } + + /** + * Handle the description area of a DocBlock + * + * This method simply finds inline tags and highlights them + * separately from the rest of the description. + * @uses getInlineTags() + * @access private + */ + function handleDesc($desc) + { + $dbtype = 'docblock'; + $dbtype .= ($this->_pf_docblock ? '' : 'template'); + foreach($desc as $line) + { + $this->getInlineTags($line[0].$line[1]); + if (strpos($line[0],'*/') === false) + { + $this->newLineNum(); + $this->_wp->linenum++; + } + } + if ($this->_pf_internal) + { + $this->_pf_internal = false; + } + } + + /** + * Handle phpDocumentor tags in a DocBlock + * + * This method uses the {@link $tagHandlers} array to determine which + * method will handle tags found in the docblock, and passes the data to + * the individual handlers one by one + * @access private + */ + function handleTags($tags) + { + $newtags = array(); + $curtag = array(); + for($i=0;$i < count($tags);$i++) + { + $tagsi = trim($tags[$i][1]); + if (substr($tagsi,0,1) == '@' && substr($tagsi,0,2) != '@ ') + { // start a new tag + $tags[$i][1] = array(substr($tags[$i][1],0,strpos($tags[$i][1],$tagsi)),$tagsi); + if (!empty($curtag)) + { + $newtags[] = $curtag; + $curtag = array(); + } + $curtag[] = $tags[$i]; + } else $curtag[] = $tags[$i]; + } + if (!empty($curtag)) $newtags[] = $curtag; + foreach($newtags as $tag) + { + foreach($tag as $i => $t) + { + if ($t[1] === false) continue; + if (is_array($t[1])) + { + $tag[$i][1][1] = explode(" ",str_replace("\t",' ',$t[1][1])); + $x = $tag[$i][1][1]; + } + } + $tagname = substr(array_shift($x),1); + $restoftag = $tag; + if (isset($this->tagHandlers[$tagname])) + $handle = $this->tagHandlers[$tagname]; + else + $handle = $this->tagHandlers['*']; + $this->$handle($tagname,$restoftag); + } + } + + /** + * This handler recognizes all {@}inline} tags + * + * Normal inline tags are simply highlighted. the {@}internal}} inline + * tag {@tutorial tags.inlineinternal.pkg} is highlighted differently + * to distinguish it from other inline tags. + * @access private + */ + function getInlineTags($value, $endinternal = false) + { + if (!$value) return; + if ($this->_pf_internal && !$endinternal) + { + if (strpos($value,'}}') !== false) + { + $x = strrpos($value,'}}'); + // add the rest of internal + $this->getInlineTags(substr($value,0,$x + 3), true); + // strip internal from value + $value = substr($value,strrpos($value,'}}') + 1); + // turn off internal + $this->_pf_internal = false; + } + } + if (!$value) return; + $dbtype = 'docblock'; + $dbtype .= ($this->_pf_docblock ? '' : 'template'); + $save = $value; + $value = explode('{@',$value); + $newval = array(); + // everything before the first {@ is normal text + $this->_addDocBlockoutput($dbtype, $value[0]); + for($i=1;$i_addDocBlockoutput($dbtype, '{@}'.substr($value[$i],1)); + } else + { + $save = $value[$i]; + $value[$i] = str_replace("\t"," ",$value[$i]); + $value[$i] = explode(" ",$value[$i]); + $word = array_shift($value[$i]); + $val = join(' ',$value[$i]); + if ($word == 'internal') + { + $this->_pf_internal = true; + $this->_addDocBlockoutput($dbtype, '{@internal '); + $value[$i] = substr($save,strlen('internal') + 1); + // strip internal and cycle as if it were normal text. + $this->_addDocBlockoutput($dbtype, $value[$i]); + continue; + } + if (in_array(str_replace('}','',$word),$this->allowableInlineTags)) + { + if (strpos($word,'}')) + { + $word = str_replace('}','',$word); + $val = '} '.$val; + } + $val = explode('}',$val); + if (count($val) == 1) + { +// addError(PDERROR_UNTERMINATED_INLINE_TAG,$word,'',$save); + } + $rest = $val; + $val = array_shift($rest); + if ($endinternal) + $rest = join('}',$rest); + else + $rest = join(' ',$rest); + if (isset($this->inlineTagHandlers[$word])) + $handle = $this->inlineTagHandlers[$word]; + else + $handle = $this->inlineTagHandlers['*']; + $this->$handle($word,$val); + $this->_addDocBlockoutput($dbtype, $rest); + } else + { + $val = $word.' '.$val; + $this->_addDocBlockoutput($dbtype, '{@'.$val); + } + } + } + } + + + /** + * Handles all inline tags + * @access private + */ + function handleDefaultInlineTag($name, $value) + { + $this->_addDocBlockoutput('inlinetag','{@'.$name.' '.$value.'}'); + } + + /**#@+ + * phpDocumentor DocBlock tag handlers + * @access private + * @param string tag name + * @param array array of lines contained in the tag description + */ + /** + * Handle normal tags + * + * This handler adds to outpu all comment information before the tag begins + * as in " * " before "@todo" in " * @todo" + * + * Then, it highlights the tag as a regular or coretag based on $coretag. + * Finally, it uses getInlineTags to highlight the description + * @uses getInlineTags() highlight a tag description + * @param boolean whether this tag is a core tag or not + */ + function defaultTagHandler($name, $value, $coretag = false) + { + $dbtype = 'docblock'; + $dbtype .= ($this->_pf_docblock ? '' : 'template'); + foreach($value as $line) + { + $this->_addDocBlockoutput($dbtype, $line[0]); + if ($line[1] === false) + { + if (trim($line[0]) != '*/') + { + $this->newLineNum(); + $this->_wp->linenum++; + } + continue; + } + $this->_addDocBlockoutput($dbtype, $line[1][0]); + $stored = ''; + if (is_array($line[1][1])) + { + foreach($line[1][1] as $i => $tpart) + { + if ($tpart == '@'.$name && $i == 0) + { + $tagname = 'tag'; + if ($coretag) $tagname = 'coretag'; + $this->_addDocBlockoutput($tagname,'@'.$name); + continue; + } + $stored .= ' '.$tpart; + } + } else $stored = $line[1]; + $this->getInlineTags($stored); + if (strpos($stored,'*/') === false) + { + $this->newLineNum(); + $this->_wp->linenum++; + } + } + } + + /** + * @see defaultTagHandler() + */ + function coreTagHandler($name, $value) + { + return $this->defaultTagHandler($name, $value, true); + } + + /** + * Handles @global + * + * This handler works like {@link defaultTagHandler()} except it highlights + * the type and variable (if present) in "@global type $variable" or + * "@global type description" + */ + function globalTagHandler($name, $value) + { + $this->paramTagHandler($name, $value); + } + + /** + * Handles @param + * + * This handler works like {@link defaultTagHandler()} except it highlights + * the type and variable (if present) in "@param type $variable description" + * or "@param type description" + * @param boolean private parameter, checks for $var or not + */ + function paramTagHandler($name, $value, $checkforvar = true) + { + $dbtype = 'docblock'; + $dbtype .= ($this->_pf_docblock ? '' : 'template'); + $ret = $this->retrieveType($value,0,$checkforvar); + foreach($value as $num => $line) + { + $this->_addDocBlockoutput($dbtype, $line[0]); + if ($line[1] === false) + { + if (trim($line[0]) != '*/') + { + $this->newLineNum(); + $this->_wp->linenum++; + } + continue; + } + $this->_addDocBlockoutput($dbtype, $line[1][0]); + $stored = ''; + $typeloc = 1; + $varloc = 2; + if (is_array($line[1][1])) + { + $this->_addDocBlockoutput('coretag','@'.$name.' '); + foreach($ret[0] as $text) + { + if (is_string($text)) $this->_addDocBlockoutput($dbtype,$text); + if (is_array($text)) + { + if ($text[0] != 'desc') $this->_addDocBlockoutput($text[0],$text[1]); + else $stored .= $text[1]; + } + } + } else + { + if (isset($ret[$num])) + { + foreach($ret[$num] as $text) + { + if (is_string($text)) $this->_addDocBlockoutput($dbtype,$text); + if (is_array($text)) + { + if ($text[0] != 'desc') $this->_addDocBlockoutput($text[0],$text[1]); + else $stored .= $text[1]; + } + } + } else $stored = $line[1]; + } + $this->getInlineTags($stored); + if (strpos($stored,'*/') === false) + { + $this->newLineNum(); + $this->_wp->linenum++; + } + } + } + + /** + * @see paramTagHandler() + */ + function staticvarTagHandler($name, $value) + { + return $this->paramTagHandler($name, $value); + } + + /** + * @see paramTagHandler() + */ + function varTagHandler($name, $value) + { + return $this->paramTagHandler($name, $value); + } + + /** + * Handles @return + * + * This handler works like {@link defaultTagHandler()} except it highlights + * the type in "@return type description" + */ + function returnTagHandler($name, $value) + { + $this->paramTagHandler($name, $value, false); + } + /**#@-*/ + + /** + * Retrieve the type portion of a @tag type description + * + * Tags like @param, @return and @var all have a PHP type portion in their + * description. Since the type may contain the expression "object blah" + * where blah is a classname, it makes parsing out the type field complex. + * + * Even more complicated is the case where a tag variable can contain + * multiple types, such as object blah|object blah2|false, and so this + * method handles these cases. + * @param array array of words that were separated by spaces + * @param 0|1 0 = find the type, 1 = find the var, if present + * @param boolean flag to determine whether to check for the end of a + * type is defined by a $varname + * @return array Format: array(state (0 [find type], 1 [var], 2 [done]), + * + * @access private + */ + function retrieveType($value, $state = 0, $checkforvar = false) + { + $index = 0; + $result = array(); + do + { + if (!isset($value[$index][1])) return $result; + $val = $value[$index][1]; + if (empty($val)) return $result; + if ($index == 0) + { + $val = $val[1]; + array_shift($val); + } else + { + $val = explode(' ',$val); + } + $ret = $this->_retrieveType($val, $state, $checkforvar); + $state = $ret[0]; + $result[$index++] = $ret[1]; + } while ((!$checkforvar && $state < 1) || ($state < 2 && $checkforvar)); + return $result; + } + + function _retrieveType($value, $state, $checkforvar) + { + $result = array(); + $result[] = $this->_removeWhiteSpace($value, 0); + if ($state == 0) + { + if (!count($value)) return array(2,$result); + $types = ''; + $index = 0; + if (trim($value[0]) == 'object') + { + $result[] = array('tagphptype', $value[0].' '); + $types .= array_shift($value).' '; + $result[] = $this->_removeWhiteSpace($value, 0); + if (!count($value)) + { // was just passed "object" + return array(2,$result); + } + if ($value[0]{0} == '$' || substr($value[0],0,2) == '&$') + { // was just passed "object" and the next thing is a variable name + if ($checkforvar) + { + $result[] = array('tagvarname' , $value[0].' '); + array_shift($value); + } + $result[] = array('desc', join(' ', $value)); + return array(2,$result); + } + } + $done = false; + $loop = -1; + do + { // this loop checks for type|type|type and for + // type|object classname|type|object classname2 + if (strpos($value[0], '|')) + { + $temptypes = explode('|', $value[0]); + while(count($temptypes)) + { + $type = array_shift($temptypes); + $result[] = array('tagphptype',$type); + if (count($temptypes)) $result[] = '|'; + } + if (trim($type) == 'object') + { + $result[] = array('tagphptype', $types . ' '); + $result[] = $this->_removeWhiteSpace($value,0); + } else $done = true; + array_shift($value); + if (count($value) && strlen($value[0]) && isset ($value[0]) && ($value[0]{0} == '$' || substr($value[0],0,2) == '&$')) + { // was just passed "object" and the next thing is a variable name + $result[] = array('tagvarname' , $value[0].' '); + array_shift($value); + $result[] = array('desc', join(' ', $value)); + return array(2,$result); + } + } else + { + $result[] = array('tagphptype', $value[0].' '); + array_shift($value); + $done = true; + } + $loop++; + } while (!$done && count($value)); + if ($loop) $result[] = ' '; + // still searching for type + if (!$done && !count($value)) return array(0,$result); + // still searching for var + if ($done && !count($value)) return array(1,$result); + } + $result[] = $this->_removeWhiteSpace($value,0); + $state = 1; + if ($checkforvar) + { + if (count($value)) + { + $state = 2; + if (substr($value[0],0,1) == '$' || substr($value[0],0,2) == '&$') + { + $result[] = array('tagvarname' , $value[0].' '); + array_shift($value); + } + } else $state = 1; + } + $result[] = array('desc', join(' ',$value)); + return array($state,$result); + } + + + /** + * @param array array of string + * @param integer index to seek non-whitespace to + * @access private + * @return string whitespace + */ + function _removeWhiteSpace(&$value, $index) + { + $result = ''; + if (count($value) > $index && empty($value[$index])) + { + $found = false; + for($i=$index; $i_pf_colon_colon) + { + $this->_pf_colon_colon = false; + $combo = $this->_pv_last_string[1].'::'.$word[1].'()'; +// debug('testing '.$combo); + $link = $this->_converter->getLink($combo); + if (is_object($link)) + { + $this->_addoutput($this->_converter->returnSee($link, $word[1]), true); + return; + } + $this->_addoutput($word); + return; + } + $link = $this->_converter->getLink($word[1].'()'); + if (is_object($link)) + { + $this->_addoutput($this->_converter->returnSee($link, $word[1]), true); + return; + } elseif (is_string($link) && strpos($link,'ttp://')) + { + $this->_addoutput($this->_converter->returnLink($link, $word[1]), true); + return; + } else + { + $link = $this->_converter->getLink($word[1]); + if (is_object($link)) $word[1] = $this->_converter->returnSee($link, $word[1]); + $this->_addoutput($word, true); + return; + } + } + $this->_addoutput($word); + } + + /** + * Works like {@link _link()} except it only links to global variables + */ + function _globallink($word) + { + if (!is_array($word)) return $this->_addoutput($word); + if ($word[0] != T_VARIABLE) return $this->_addoutput($word); + if (is_array($word) && $word[0] == T_VARIABLE) + { + $link = $this->_converter->getLink('global '.$word[1]); + if (is_object($link)) + { + $this->_addoutput($this->_converter->returnSee($link, $word[1]), true); + return; + } + } + $this->_addoutput($word); + } + + /** + * Works like {@link _link()} except it only links to classes + */ + function _classlink($word) + { +// debug("checking class ".$word[1]); + if (is_array($word) && $word[0] == T_STRING) + { + $link = $this->_converter->getLink($word[1]); + if (is_object($link)) + { + $this->_addoutput($this->_converter->returnSee($link, $word[1]), true); + return; + } + } + $this->_addoutput($word); + } + + /** + * Works like {@link _link()} except it only links to methods + */ + function _methodlink($word) + { + if (is_array($word) && $word[0] == T_STRING) + { +// debug("checking method ".$this->_pv_class.'::'.$word[1].'()'); + if (isset($this->_pv_prev_var_type)) + { + $link = $this->_converter->getLink($this->_pv_prev_var_type.'::'.$word[1].'()'); + } else + $link = $this->_converter->getLink($this->_pv_class.'::'.$word[1].'()'); + if (is_object($link)) + { + $this->_addoutput($this->_converter->returnSee($link, $word[1]), true); + return; + } + if (isset($this->_pv_prev_var_type)) + { + $this->_addoutput($word); + return; + } +// debug("checking method ".$word[1].'()'); + $link = $this->_converter->getLink($word[1].'()'); + if (is_object($link)) + { + $this->_addoutput($this->_converter->returnSee($link, $word[1]), true); + return; + } + } + $this->_addoutput($word); + } + + /** + * Works like {@link _link()} except it only links to class variables + */ + function _varlink($word, $justastring=false) + { + if ($justastring) + { + $word[0] = T_VARIABLE; + } + if (is_array($word) && $word[0] == T_VARIABLE) + { + $x = ($justastring ? '$' : ''); +// debug("checking var ".$this->_pv_class.'::'.$x.$word[1]); + if (isset($this->_pv_prev_var_type)) + { +// debug("checking var ".$this->_pv_prev_var_type.'::'.$x.$word[1]); + $link = $this->_converter->getLink($this->_pv_prev_var_type.'::'.$x.$word[1]); + } + else + $link = $this->_converter->getLink($this->_pv_class.'::'.$x.$word[1]); + if (is_object($link)) + { + $this->_addoutput($this->_converter->returnSee($link, $word[1]), true); + return; + } +// debug("checking var ".$x.$word[1]); + if (isset($this->_pv_prev_var_type)) + { + $this->_addoutput($word); + return; + } + $link = $this->_converter->getLink($x.$word[1]); + if (is_object($link)) + { + $this->_addoutput($this->_converter->returnSee($link, $word[1]), true); + return; + } + } + $this->_addoutput($word); + } + /**#@-*/ + + /**#@+ + * Output Methods + * @access private + */ + /** + * This method adds output to {@link $_line} + * + * If a string with variables like "$test this" is present, then special + * handling is used to allow processing of the variable in context. + * @see _flush_save() + */ + function _addoutput($word, $preformatted = false) + { + if ($this->_pf_no_output_yet) return; + if ($this->_pf_quote_active) + { + if (is_array($word)) $this->_save .= $this->_converter->highlightSource($word[0], $word[1]); + else + $this->_save .= $this->_converter->highlightSource(false, $word, true); + } else + { + $this->_flush_save(); + if (is_string($word) && trim($word) == '') + { + $this->_line .= $word; + return; + } + if (is_array($word) && trim($word[1]) == '') + { + $this->_line .= $word[1]; + return; + } + if (is_array($word)) + { + $this->_line .= $this->_converter->highlightSource($word[0], $word[1], $preformatted); + } else + { + $this->_line .= $this->_converter->highlightSource(false, $word, $preformatted); + } + } + } + + /** + * Like {@link _output()}, but for DocBlock highlighting + */ + function _addDocBlockoutput($dbtype, $word, $preformatted = false) + { + if ($this->_pf_internal) + { + $this->_line .= $this->_converter->highlightDocBlockSource('internal', $word, $preformatted); + } else + { + $this->_line .= $this->_converter->highlightDocBlockSource($dbtype, $word, $preformatted); + } + } + + /** + * Flush a saved string variable highlighting + * + * {@source} + */ + function _flush_save() + { + if (!empty($this->_save)) + { + $this->_save .= $this->_converter->flushHighlightCache(); + // clear the existing cache, reset it to the old value + $this->_converter->_setHighlightCache($this->_save_highlight_state[0], $this->_save_highlight_state[1]); + $this->_line .= $this->_converter->highlightSource(T_CONSTANT_ENCAPSED_STRING, $this->_save, true); + $this->_save = ''; + } + } + /**#@-*/ + + /** + * Give the word parser necessary data to begin a new parse + * @param array all tokens separated by line number + */ + function configWordParser(&$data) + { + $this->_wp->setup($data, $this); + $this->_wp->setWhitespace(true); + } + + /** + * Initialize all parser state variables + * @param boolean true if we are highlighting an inline {@}source} tag's + * output + * @param false|string name of class we are going to start from + * @uses $_wp sets to a new {@link phpDocumentor_HighlightWordParser} + */ + function setupStates($inlinesourceparse, $class) + { + $this->_output = ''; + $this->_line = ''; + unset($this->_wp); + $this->_wp = new phpDocumentor_HighlightWordParser; + $this->_event_stack = new EventStack; + if ($inlinesourceparse) + { + $this->_event_stack->pushEvent(PARSER_EVENT_PHPCODE); + if ($class) + { + $this->_event_stack->pushEvent(PARSER_EVENT_CLASS); + $this->_pv_class = $class; + } + } else $this->_pv_class = null; + $this->_pv_define = null; + $this->_pv_define_name = null; + $this->_pv_define_value = null; + $this->_pv_define_params_data = null; + $this->_pv_dtype = null; + $this->_pv_docblock = null; + $this->_pv_dtemplate = null; + $this->_pv_func = null; + $this->_pv_global_name = null; + $this->_pv_global_val = null; + $this->_pv_globals = null; + $this->_pv_global_count = null; + $this->_pv_include_params_data = null; + $this->_pv_include_name = null; + $this->_pv_include_value = null; + $this->_pv_linenum = null; + $this->_pv_periodline = null; + $this->_pv_paren_count = 0; + $this->_pv_statics = null; + $this->_pv_static_count = null; + $this->_pv_static_val = null; + $this->_pv_quote_data = null; + $this->_pv_function_data = null; + $this->_pv_var = null; + $this->_pv_varname = null; + $this->_pf_definename_isset = false; + $this->_pf_extends_found = false; + $this->_pf_includename_isset = false; + $this->_pf_get_source = false; + $this->_pf_getting_source = false; + $this->_pf_in_class = false; + $this->_pf_in_define = false; + $this->_pf_in_global = false; + $this->_pf_in_include = false; + $this->_pf_in_var = false; + $this->_pf_funcparam_val = false; + $this->_pf_quote_active = false; + $this->_pf_reset_quote_data = true; + $this->_pf_useperiod = false; + $this->_pf_var_equals = false; + $this->_pf_obj_op = false; + $this->_pf_docblock = false; + $this->_pf_docblock_template = false; + $this->_pf_colon_colon = false; + $this->_pv_last_string = false; + $this->_pf_inmethod = false; + $this->_pf_no_output_yet = false; + $this->_pv_saveline = 0; + $this->_pv_next_word = false; + $this->_save = ''; + } + + /** + * Initialize the {@link $tokenpushEvent, $wordpushEvent} arrays + */ + function phpDocumentor_HighlightParser() + { + if (!defined('T_INTERFACE')) { + define('T_INTERFACE', -1); + } + $this->allowableTags = $GLOBALS['_phpDocumentor_tags_allowed']; + $this->allowableInlineTags = $GLOBALS['_phpDocumentor_inline_doc_tags_allowed']; + $this->inlineTagHandlers = array('*' => 'handleDefaultInlineTag'); +/**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_NOEVENTS] = + array( + T_OPEN_TAG => PARSER_EVENT_PHPCODE, + ); + +/**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_PHPCODE] = + array( + T_FUNCTION => PARSER_EVENT_FUNCTION, + T_CLASS => PARSER_EVENT_CLASS, + T_INTERFACE => PARSER_EVENT_CLASS, + T_INCLUDE_ONCE => PARSER_EVENT_INCLUDE, + T_INCLUDE => PARSER_EVENT_INCLUDE, + T_START_HEREDOC => PARSER_EVENT_EOFQUOTE, + T_REQUIRE => PARSER_EVENT_INCLUDE, + T_REQUIRE_ONCE => PARSER_EVENT_INCLUDE, + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpushEvent[PARSER_EVENT_PHPCODE] = + array( + "define" => PARSER_EVENT_DEFINE, + ); +/**************************************************************/ + + $this->wordpushEvent[PARSER_EVENT_FUNCTION] = + array( + '{' => PARSER_EVENT_LOGICBLOCK, + '(' => PARSER_EVENT_FUNCTION_PARAMS, + ); + $this->tokenpushEvent[PARSER_EVENT_FUNCTION] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + + $this->wordpopEvent[PARSER_EVENT_FUNCTION] = array("}"); +/**************************************************************/ + + $this->tokenpopEvent[PARSER_EVENT_EOFQUOTE] = array(T_END_HEREDOC); +/**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_FUNCTION_PARAMS] = + array( + T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE, + T_ARRAY => PARSER_EVENT_ARRAY, + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpushEvent[PARSER_EVENT_FUNCTION_PARAMS] = + array( + '"' => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_QUOTE, + ); + $this->wordpopEvent[PARSER_EVENT_FUNCTION_PARAMS] = array(")"); +/**************************************************************/ + + $this->wordpushEvent[PARSER_EVENT_LOGICBLOCK] = + array( + "{" => PARSER_EVENT_LOGICBLOCK, + '"' => PARSER_EVENT_QUOTE, + ); + $this->tokenpushEvent[PARSER_EVENT_LOGICBLOCK] = + array( + T_GLOBAL => PARSER_EVENT_FUNC_GLOBAL, + T_STATIC => PARSER_EVENT_STATIC_VAR, + T_START_HEREDOC => PARSER_EVENT_EOFQUOTE, + T_CURLY_OPEN => PARSER_EVENT_LOGICBLOCK, + T_DOLLAR_OPEN_CURLY_BRACES => PARSER_EVENT_LOGICBLOCK, + ); + + $this->wordpopEvent[PARSER_EVENT_LOGICBLOCK] = array("}"); + $this->tokenpopEvent[PARSER_EVENT_LOGICBLOCK] = array(T_CURLY_OPEN); + +/**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_ARRAY] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpopEvent[PARSER_EVENT_ARRAY] = array(")"); +/**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_FUNC_GLOBAL] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + + $this->wordpopEvent[PARSER_EVENT_FUNC_GLOBAL] = array(";"); +/**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_STATIC_VAR] = + array( + T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE, + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpushEvent[PARSER_EVENT_STATIC_VAR] = + array( + "=" => PARSER_EVENT_STATIC_VAR_VALUE, + ); + $this->wordpopEvent[PARSER_EVENT_STATIC_VAR] = array(";"); +/**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_STATIC_VAR_VALUE] = + array( + T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE, + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + T_ARRAY => PARSER_EVENT_ARRAY, + ); + $this->wordpushEvent[PARSER_EVENT_STATIC_VAR_VALUE] = + array( + '"' => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_QUOTE, + ); + $this->wordpopEvent[PARSER_EVENT_STATIC_VAR_VALUE] = array(";",","); +/**************************************************************/ + $this->tokenpushEvent[PARSER_EVENT_QUOTE] = + array( + T_OBJECT_OPERATOR => PARSER_EVENT_CLASS_MEMBER, + T_CURLY_OPEN => PARSER_EVENT_QUOTE_VAR, + ); + + $this->wordpopEvent[PARSER_EVENT_QUOTE] = array('"'); +/**************************************************************/ + $this->tokenpushEvent[PARSER_EVENT_QUOTE_VAR] = + array( + T_OBJECT_OPERATOR => PARSER_EVENT_CLASS_MEMBER, + T_CURLY_OPEN => PARSER_EVENT_QUOTE_VAR, + ); + + $this->wordpushEvent[PARSER_EVENT_QUOTE_VAR] = + array( + "{" => PARSER_EVENT_QUOTE_VAR, + '"' => PARSER_EVENT_QUOTE_VAR, + "'" => PARSER_EVENT_QUOTE_VAR, + ); + $this->wordpopEvent[PARSER_EVENT_QUOTE_VAR] = array('}'); +/**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_DEFINE] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE, + ); + $this->wordpushEvent[PARSER_EVENT_DEFINE] = + array( + "(" => PARSER_EVENT_DEFINE_PARAMS, + ); + $this->wordpopEvent[PARSER_EVENT_DEFINE] = array(";"); +/**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_DEFINE_PARAMS] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpushEvent[PARSER_EVENT_DEFINE_PARAMS] = + array( + "(" => PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS, + '"' => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_QUOTE, + ); + $this->wordpopEvent[PARSER_EVENT_DEFINE_PARAMS] = array(")"); +/**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpushEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] = + array( + "(" => PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS, + '"' => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_QUOTE, + ); + $this->wordpopEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] = array(")"); +/**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_VAR] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + T_ARRAY => PARSER_EVENT_ARRAY, + ); + $this->wordpopEvent[PARSER_EVENT_VAR] = array(";"); +/**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_CLASS] = + array( + T_FUNCTION => PARSER_EVENT_METHOD, + T_VAR => PARSER_EVENT_VAR, + T_COMMENT => PARSER_EVENT_DOCBLOCK, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + T_CLOSE_TAG => PARSER_EVENT_OUTPHP, + ); + $this->wordpopEvent[PARSER_EVENT_CLASS] = array("}"); + +/**************************************************************/ + + $this->wordpushEvent[PARSER_EVENT_METHOD] = + array( + '{' => PARSER_EVENT_METHOD_LOGICBLOCK, + '(' => PARSER_EVENT_FUNCTION_PARAMS, + ); + $this->tokenpushEvent[PARSER_EVENT_METHOD] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + + $this->wordpopEvent[PARSER_EVENT_METHOD] = array("}", ";"); +/**************************************************************/ + + $this->wordpushEvent[PARSER_EVENT_METHOD_LOGICBLOCK] = + array( + "{" => PARSER_EVENT_METHOD_LOGICBLOCK, + '"' => PARSER_EVENT_QUOTE, + ); + $this->tokenpushEvent[PARSER_EVENT_METHOD_LOGICBLOCK] = + array( + T_OBJECT_OPERATOR => PARSER_EVENT_CLASS_MEMBER, + T_GLOBAL => PARSER_EVENT_FUNC_GLOBAL, + T_STATIC => PARSER_EVENT_STATIC_VAR, + T_CURLY_OPEN => PARSER_EVENT_LOGICBLOCK, + T_DOLLAR_OPEN_CURLY_BRACES => PARSER_EVENT_LOGICBLOCK, + ); + + $this->wordpopEvent[PARSER_EVENT_METHOD_LOGICBLOCK] = array("}"); + $this->tokenpopEvent[PARSER_EVENT_METHOD_LOGICBLOCK] = array(T_CURLY_OPEN); +/**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_INCLUDE] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpushEvent[PARSER_EVENT_INCLUDE] = + array( + "(" => PARSER_EVENT_INCLUDE_PARAMS, + ); + $this->wordpopEvent[PARSER_EVENT_INCLUDE] = array(";"); +/**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_INCLUDE_PARAMS] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpushEvent[PARSER_EVENT_INCLUDE_PARAMS] = + array( + "(" => PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS, + ); + $this->wordpopEvent[PARSER_EVENT_INCLUDE_PARAMS] = array(")"); +/**************************************************************/ + + $this->tokenpushEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] = + array( + T_COMMENT => PARSER_EVENT_COMMENT, + T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK, + ); + $this->wordpushEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] = + array( + "(" => PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS, + ); + $this->wordpopEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] = array(")"); + } +} +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/InlineTags.inc b/buildscripts/PhpDocumentor/phpDocumentor/InlineTags.inc new file mode 100644 index 00000000..1bea7734 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/InlineTags.inc @@ -0,0 +1,854 @@ + + * @since 1.0rc1 + * @version $Revision: 1.1 $ + * @tutorial inlinetags.pkg + */ +class parserInlineTag extends parserBase +{ + /** + * Element type + * + * Type is used by many functions to skip the hassle of + * + * + * if phpDocumentor_get_class($blah) == 'parserBlah' + * + * always "inlinetag" + * @var string + */ + var $type = 'inlinetag'; + /** + * the name of the inline tag (like link) + * @var string + */ + var $inlinetype = ''; + + /** + * @param string $type tag type (example: link) + * @param string $value tag value (example: what to link to) + */ + function parserInlineTag($type,$value) + { + $this->inlinetype = $type; + $this->value = trim($value); + } + + /** + * @return integer length of the tag + */ + function Strlen() + { + // fix 1203451 + if (is_array($this->value)) + { + return array_reduce(create_function('$a,$b', 'return $a + strlen($b);')) + + count($this->value); + } + return strlen($this->value); + } + + /** + * @return string always '', used by {@link Parser::handleDocBlock()} to + * calculate the short description of a DocBlock + * @see parserStringWithInlineTags::getString() + * @see parserStringWithInlineTags::trimmedStrlen() + */ + function getString() + { + return ''; + } +} + +/** + * represents inline links + * @tutorial tags.inlinelink.pkg + * @package phpDocumentor + * @subpackage InlineTags + * @author Greg Beaver + * @since 1.0rc1 + */ +class parserLinkInlineTag extends parserInlineTag +{ + /** + * text to display in the link, can be different from the link for standard + * links like websites + * @var string + */ + var $linktext = ''; + + /** + * @param string $link stored in $value, see {@link parserBase::$value} + * @param string $text see {@link $linktext} + */ + function parserLinkInlineTag($link,$text) + { + if (strpos($link, ',')) + { + $link = explode(',',$link); + parserInlineTag::parserInlineTag('link',''); + $this->value = $link; + } else + { + parserInlineTag::parserInlineTag('link',$link); + } + $this->linktext = trim($text); + } + + /** + * @param Converter converter used to change the abstract link into text for + * display + * @return false|string returns the converted link or false if not converted + * successfully + */ + function Convert(&$c) + { + if (is_array($this->value)) + { + $ret = ''; + foreach($this->value as $text) + { + if (!empty($ret)) + { + $ret .= ', '; + } + $ret .= $this->ConvertPart($c, trim($text)); + } + return $ret; + } else + { + return $this->ConvertPart($c, $this->value); + } + } + + function ConvertPart(&$c, $value) + { + if (strpos($value,'://') || (strpos($value,'mailto:') === 0)) + { + if (strpos($value, ' ')) + { + $value = explode(' ', $value); + $link = array_shift($value); + $text = join(' ', $value); + } else + { + $link = $value; + $text = $this->linktext; + } + return $c->returnLink($link,htmlspecialchars($text)); + } else + { + $savevalue = $value; + $descrip = false; + if (strpos(trim($value),' ')) + { + $v = preg_split('/\s/',trim($value)); + if (in_array(strtolower($v[0]), array('object', 'function'))) + { + if (!isset($v[1]) || + (isset($v[1]) && strlen($v[1]) + && !in_array($v[1]{0}, array('$','&')) + && $v[1] != '###commanana####')) + { + $vsave = $v[0]; + array_shift($v); + $v[0] = $vsave . ' ' . $v[0]; + } + } + $value = $c->getLink($v[0]); + array_shift($v); + $descrip = join($v,' '); + $descrip = str_replace('###commanana####', ',', $descrip); + } else + { + $value = $c->getLink($value); + } + if (is_string($value)) + { + // feature 564991 + if (strpos($value,'://')) + { + // php function + return $c->returnLink($value,str_replace('PHP_MANUAL#','',$value)); + } + return $value; + } + if (!$descrip) $descrip = $c->type_adjust($savevalue); + if (is_object($value)) return $c->returnSee($value, $descrip); +/* // getLink parsed a comma-delimited list of linked thingies, add the commas back in + if (is_array($value)) + { + $a = ''; + foreach($value as $i => $bub) + { + if (!empty($a)) $a .= ', '; + if (is_string($value[$i])) + { + // feature 564991 + if (strpos($value[$i],'://')) + { + // php function + $a .= $c->returnLink($value[$i],str_replace('PHP_MANUAL#','',$vals[$i])); + } else + $a .= $value[$i]; + } + if (is_object($value[$i])) $a .= $c->returnSee($value[$i],$descrip[$i]); + } + return $a; + } */ + return $savevalue; + } + } +} + +/** + * Represents inline links to external tutorial documentation + * @tutorial tags.inlinetutorial.pkg + * @package phpDocumentor + * @subpackage InlineTags + */ +class parserTutorialInlineTag extends parserLinkInlineTag +{ + /** + * @param string $link stored in $value, see {@link parserBase::$value} + * @param string $text see {@link $linktext} + */ + function parserTutorialInlineTag($link,$text) + { + parserInlineTag::parserInlineTag('tutorial',$link); + $this->linktext = trim($text); + } + + /** + * @param Converter converter used to change the abstract link into text for display + * @return mixed returns the converted link or false if not converted successfully + */ + function Convert(&$c) + { + $descrip = false; + if (strpos($this->value,',') === false) + { + if (strpos(trim($this->value),' ')) + { + $v = split(' ',trim($this->value)); + $value = $c->getTutorialLink($v[0]); + array_shift($v); + $descrip = join($v,' '); + } else $value = $c->getTutorialLink($this->value); + } else + { + $vals = split(',',$this->value); + $descrip = array(); + foreach($vals as $val) + { + $val = trim($val); + if (strpos($val,' ')) + { + $v = split(' ',$val); + $value[] = $c->getTutorialLink($v[0]); + array_shift($v); + $descrip[] = join($v,' '); + } else + { + $value[] = $c->getTutorialLink($val); + $descrip[] = false; + } + } + } + if (is_string($value)) + { + return $value; + } + if (is_object($value)) return $c->returnSee($value,$descrip); + // getLink parsed a comma-delimited list of linked thingies, add the commas back in + if (is_array($value)) + { + $a = ''; + foreach($value as $i => $bub) + { + if (!empty($a)) $a .= ', '; + if (is_string($value[$i])) + { + $a .= $value[$i]; + } + if (is_object($value[$i])) $a .= $c->returnSee($value[$i],$descrip[$i]); + } + return $a; + } + return false; + } +} + +/** + * represents inline source tag, used for function/method source + * @tutorial tags.inlinesource.pkg + * @package phpDocumentor + * @subpackage InlineTags + */ +class parserSourceInlineTag extends parserInlineTag +{ + /** + * always 'source' + * @var string + */ + var $inlinetype = 'source'; + /** + * First line of source code to display + * @var integer + * @see $end + */ + var $start = 1; + /** + * Last line to display + * @var '*'|integer If '*' then the whole source will be used, otherwise + * the {@link $start} to $end line numbers will be displayed + */ + var $end = '*'; + /** + * tokenized source organized by line numbers for php 4.3.0+, the old + * {@}source} tag used a string + * @var string|array + */ + var $source = false; + /**#@+ @access private */ + /** @var string|false */ + var $_class; + /**#@-*/ + /** + * @param string format "start [end]" where start and end are line numbers + * with the end line number optional + */ + function parserSourceInlineTag($value) + { + parserInlineTag::parserInlineTag('source',''); + preg_match('/^([0-9]*)\W([0-9]*)$/',trim($value), $match); + if (!count($match)) + { + preg_match('/^([0-9]*)$/',trim($value),$match); + if (count($match)) + { + $this->start = (int) $match[1]; + } + } else + { + $this->start = (int) $match[1]; + $this->end = (int) $match[2]; + } + } + + /** + * only used to determine blank lines. {@}source} will not be blank, + * probably + */ + function Strlen() + { + return 1; + } + + function getString() + { + return '{@source}'; + } + + /** + * @param string|array source code + * @param boolean in php 4.3.0, if this is a method this will be true + * @param string class name if this is a method + */ + function setSource($source, $class = false) + { + if (is_array($source)) + { + $this->_class = $class; + $this->source = $source; + } else + { + $source = strstr($source,'function'); + $pos = strrpos($source,'}'); + $this->source = substr($source,0,$pos + 1); + } + } + + /** + * @uses stringConvert() in PHP 4.2.3-, this method is used to convert + * @uses arrayConvert() in PHP 4.3.0+, this method is used to convert + * @param Converter + */ + function Convert(&$c) + { + if (is_string($this->source)) return $this->stringConvert($c); + return $this->arrayConvert($c); + } + + /** + * @param Converter + * @uses phpDocumentor_HighlightParser Parses the tokenized source + */ + function arrayConvert(&$c) + { + $source = $this->source; + if ($this->end != '*') + { + $source = array_slice($this->source,0,$this->end + $this->start - 1); + } + $start = $this->start - 1; + if ($start < 0) $start = 0; + return $c->ProgramExample($source, true, true, $this->_class, $start); + } + + /** + * @param Converter + * @uses Converter::unmangle() remove the extraneous stuff from + * {@link highlight_string()} + * @deprecated in favor of PHP 4.3.0+ {@link arrayConvert()} + */ + function stringConvert(&$c) + { + $source = highlight_string('source.' ?>', true); + $source = ''.substr($source,strlen(' +<?php ') - 1); + $source = str_replace('} ?>','}',$source); + if ($this->start || ($this->end != '*')) + { + $source = explode('
            ',$source); + $start = $this->start; + if ($this->end != '*') + { + $source = array_slice($source,$start - 1,$this->end - $start + 1); + } else + { + $source = array_slice($source,$start - 1); + } + $source = implode($source,'
            '); + if ($start > 0) $source = "$source"; + if ($this->end != '*') $source = "$source"; + } + $source = $c->unmangle($source,$this->source); + return $source; + } +} + +/** + * Represents the example inline tag, used to display an example file + * inside a docblock or tutorial + * @tutorial tags.inlineexample.pkg + * @package phpDocumentor + * @subpackage InlineTags + */ +class parserExampleInlineTag extends parserSourceInlineTag +{ + /** + * @param string format "filepath[ start [end]]" where start and end are line numbers + * with the end line number optional + * @param string full path to the current file, used to check relative + * directory locations + * @param boolean if true, then this is in a tutorial + */ + function parserExampleInlineTag($value, $current_path, $isTutorial = false) + { + global $_phpDocumentor_setting; + parserInlineTag::parserInlineTag('example',''); + $path = false; + $tagValue = trim($value); + $path = $isAbsPath = $pathOnly = $fileName = $fileExt = $original_path = $title = FALSE; + do + { + // make sure the format is stuff.ext startline[ endline] + if (!preg_match('`(.*)\.(\w*)\s(.*)`', $tagValue, $match)) + { + // or format is stuff.ext + if (!preg_match('`(.*)\.(\w*)\s*$`', $tagValue, $match)) + { + // Murphy: Some funny path was given + $original_path = $tagValue; // used for error output + break; // try-block + } + } + if (strlen($match[1]) === 0) + { + // Murphy: Some funny path was given + $original_path = $tagValue; // used for error output + break; // try-block + } + $fileExt = $match[2]; + if (isset($match[3])) + { + $lines = explode(' ', trim($match[3])); + $this->start = (int) $lines[0]; + if (isset($lines[1])) { + $this->end = (int) $lines[1]; + } + } + $pathTmp = str_replace('\\', '/', $match[1]); // Replace windows '\' the path. + + // Is there a path and a file or is it just a file? + if (strpos($pathTmp,'/') === false) + { + // No path part + $pathOnly = ''; + $fileName = $pathTmp .'.'. $fileExt; + } else + { + $splitPos = strrpos($pathTmp,'/'); // split the path on the last directory, find the filename + $pathOnly = substr($match[1], 0, $splitPos+1); + $fileName = substr($match[1], $splitPos+1) .'.'. $fileExt; + // Is the path absolute? (i.e. does it start like an absolute path?) + if (('/' === $pathTmp[0]) || preg_match('`^\w*:`i', $pathTmp)) + { // works for both windows 'C:' and URLs like 'http://' + $isAbsPath = true; // Yes + } + } + + $original_path = $pathOnly . $fileName; + + // Now look for the file starting with abs. path. + if ($isAbsPath) + { + $tmp = realpath($original_path); // remove any weirdities like /../file.ext + if ($tmp && is_file($tmp)) + { + $path = $tmp; + } + // Alway break if abs. path was detected; even if file was not found. + break; // try-block + } + + // Search for the example file some standard places + // 1) Look if the ini-var examplesdir is set and look there ... + if (isset($_phpDocumentor_setting['examplesdir'])) + { + $tmp = realpath($_phpDocumentor_setting['examplesdir'] . PATH_DELIMITER . $original_path); + if ($tmp && is_file($tmp)) + { + $path = $tmp; // Yo! found it :) + break; // try-block + } + } + + // 2) Then try to look for an 'example/'-dir below the *currently* parsed file ... + if (!empty($current_path)) + { + $tmp = realpath(dirname($current_path) . PATH_DELIMITER . 'examples' . PATH_DELIMITER . $fileName); + if ($tmp && is_file($tmp)) + { + $path = $tmp; // Yo! found it :) + break; // try-block + } + } + + // 3) Then try to look for the example file below the subdir PHPDOCUMENTOR_BASE/examples/ ... + if (is_dir(PHPDOCUMENTOR_BASE . PATH_DELIMITER . 'examples')) + { + $tmp = realpath(PHPDOCUMENTOR_BASE . PATH_DELIMITER . 'examples' . PATH_DELIMITER . $original_path); + if ($tmp && is_file($tmp)) + { + $path = $tmp; // Yo! found it :) + break; // try-block + } + } + + $tmp = realpath(PHPDOCUMENTOR_BASE . PATH_DELIMITER . $original_path); + if ($tmp && is_file($tmp)) + { + $path = $tmp; // Yo! found it :) + break; // try-block + } + // If we reach this point, nothing was found and $path is false. + } while (false); + + if (!$path) + { + addWarning(PDERROR_EXAMPLE_NOT_FOUND, $original_path); + $this->path = false; + } else + { + $f = @fopen($path,'r'); + if ($f) + { + $example = fread($f,filesize($path)); + if (tokenizer_ext && !$isTutorial) + { + $obj = new phpDocumentorTWordParser; + $obj->setup($example); + $this->setSource($obj->getFileSource()); + unset($obj); + } else + { + $this->setSource($example); + } + } + } + } + + /** + * @param string|array source code + * @param boolean in php 4.3.0, if this is a method this will be true + * @param string class name if this is a method + */ + function setSource($source, $class = false) + { + $this->_class = $class; + $this->source = $source; + } + + /** + * @param Converter + * @uses phpDocumentor_HighlightParser Parses the tokenized source + */ + function arrayConvert(&$c) + { + $source = $this->source; + if ($this->end != '*') + { + $source = array_slice($this->source,0,$this->end + $this->start - 1); + } + $start = $this->start - 1; + if ($start < 0) $start = 0; + return $c->exampleProgramExample($source, true, true, $this->_class, $start); + } + + /** + * Return the source for the example file, enclosed in + * a tag to use in a tutorial + * @return string + */ + function getProgramListing() + { + $source = explode("\n", $this->source); + $start = $this->start; + if ($this->end != '*') + { + $source = array_slice($source,$start - 1,$this->end - $start + 1); + } else + { + $source = array_slice($source,$start - 1); + } + $source = join("\n", $source); + return + " + \n"; + } +} + +/** + * Represents the inheritdoc inline tag, used by classes/methods/vars to inherit + * documentation from the parent class if possible + * @tutorial tags.inlineinheritdoc.pkg + * @package phpDocumentor + * @subpackage InlineTags + */ +class parserInheritdocInlineTag extends parserInlineTag +{ + /** + * always 'inheritdoc' + * @var string + */ + var $inlinetype = 'inheritdoc'; + + /** + * Does nothing, overrides parent constructor + */ + function parserInheritdocInlineTag() + { + } + + function Convert() + { + addWarning(PDERROR_INHERITDOC_DONT_WORK_HERE); + return ''; + } +} + +/** + * Represents the inline {@}id} tag for tutorials + * @tutorial tags.inlineid.pkg + * @package phpDocumentor + * @subpackage InlineTags + */ +class parserIdInlineTag extends parserInlineTag +{ + /** + * always 'id' + * @var string + */ + var $inlinetype = 'id'; + /** + * package of the {@}id} + * @var string + */ + var $package = 'default'; + /** + * category of the {@}id} + * @var string + */ + var $category = 'default'; + /** + * subpackage of the {@}id} + * @var string + */ + var $subpackage = ''; + /** + * full name of the tutorial + * @var string + */ + var $tutorial; + /** + * section/subsection name + * @var string + */ + var $id; + + /** + * @param string package name + * @param string subpackage name + * @param string tutorial name + * @param string section/subsection name + * @param string category name + */ + function parserIdInlineTag($category,$package,$subpackage,$tutorial,$id = false) + { + $this->package = $package; + $this->subpackage = $subpackage; + $this->tutorial = $tutorial; + $this->id = $id; + $this->category = $category; + } + + /** + * @param Converter + * @uses Converter::getTutorialId() retrieve converter-specific ID + */ + function Convert(&$c) + { + if (!$this->id) return ''; + return $c->getTutorialId($this->package,$this->subpackage,$this->tutorial,$this->id,$this->category); + } +} + +/** + * Represents {@}toc} for table of contents generation in tutorials + * @tutorial tags.inlinetoc.pkg + * @package phpDocumentor + * @subpackage InlineTags + */ +class parserTocInlineTag extends parserInlineTag +{ + /** + * always 'toc' + * @var string + */ + var $inlinetype = 'toc'; + /** + * @var array format: + *
            +     * array(array('tagname' => section,
            +     *             'link' => returnsee link,
            +     *             'id' => anchor name,
            +     *             'title' => from title tag),...)
            +     * 
            + * @access private + */ + var $_toc = false; + /** + * full path to tutorial, used in conversion + * @var string + * @access private + */ + var $_path = false; + + function parserTocInlineTag() + { + parent::parserInlineTag('toc',''); + } + + /** + * @param array format: + *
            +     * array(array('tag' => {@link parserXMLDocBookTag},
            +     *             'id' => {@link parserIdInlineTag},
            +     *             'title' => {@link parserXMLDocBookTag title}),...)
            +     * 
            + */ + function setTOC($toc) + { + $this->toc = $toc; + } + + /** + * @param string + */ + function setPath($path) + { + $this->_path = $path; + } + + /** + * @uses Converter::formatTutorialTOC() passes an array of format: + * + *
            +     * array(
            +     *    'tagname' => string name of tag,
            +     *    'link' => {@link tutorialLink} to the tutorial,
            +     *    'id' => converter specific tutorial ID from {@link Converter::getTutorialId()}
            +     *    'title' => title of the tutorial)
            +     * 
            + * + * and returns the results as the table of contents + * @uses Converter::getTutorialId() retrieve the tutorial ID for + * @param Converter + */ + function Convert(&$c) + { + $newtoc = array(); + foreach($this->toc as $i => $toc) + { + if (isset($toc['title'])) + $toc['tag']->setTitle($toc['title']); + else + $toc['tag']->setTitle(new parserStringWithInlineTags); + $newtoc[$i]['tagname'] = $toc['tag']->name; + $l = new tutorialLink; + if (!isset($toc['title'])) $title = 'section '.$toc['id']->id; + else + $title = $toc['title']->Convert($c); + $l->addLink($toc['id']->id,$this->_path,basename($this->_path),$toc['id']->package, $toc['id']->subpackage, strip_tags($title)); + $newtoc[$i]['link'] = $c->returnSee($l); + $newtoc[$i]['id'] = $c->getTutorialId($toc['id']->package, $toc['id']->subpackage, basename($this->_path), $toc['id']->id, $toc['id']->category); + $newtoc[$i]['title'] = $title; + } + return $c->formatTutorialTOC($newtoc); + } +} +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/IntermediateParser.inc b/buildscripts/PhpDocumentor/phpDocumentor/IntermediateParser.inc new file mode 100644 index 00000000..92a54ea0 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/IntermediateParser.inc @@ -0,0 +1,1832 @@ + parentpackagename + * @see Converter::getLink() + */ + var $package_parents = array(); + + /** + * Used to determine the category for tutorials. + * + * WARNING: If more than one category exists, the last category + * encountered will overwrite the previous and will raise a big warning + * @var array Format: packagename => categoryname + */ + var $packagecategories = array(); + + /** + * list of all packages encountered while documenting. Used in automatic + * linking. + * + * Converter::getLink() first checks if an ambiguous link is found in the + * current package. If not, it then checks in parent packages, and if still + * not found, uses this array to check in the rest of the packages before + * giving up + * @var array Format: array(packagename => 1, packagename => 1,...) + * @see Converter::getLink() + */ + var $all_packages = array(); + + /** + * array of packages to parser and output documentation for, if not all + * packages should be documented + * + * Format:
            + * array(package1,package2,...)
            + * or false if not set + * + * Use this option to limit output similar to ignoring files. If you have + * some temporary files that you don't want to specify by name but don't + * want included in output, set a package name for all the elements in your + * project, and set packageoutput to that name. the default package will be + * ignored. Parsing speed does not improve. If you want to ignore files + * for speed reasons, use the ignore command-line option + * @tutorial phpDocumentor.howto.pkg#using.command-line.packageoutput + * @see Io + * @var false|array + */ + var $packageoutput = false; + + /** + * the functions which handle output from the {@link Parser} + * @see handleEvent(), handleDocBlock(), handlePage(), handleClass() + * @see handleDefine(), handleFunction(), handleMethod(), handleVar() + * @see handlePackagePage(), handleInclude(), handleTutorial() + */ + var $event_handlers = array( + 'docblock' => 'handleDocBlock', + 'page' => 'handlePage', + 'class' => 'handleClass', + 'define' => 'handleDefine', + 'function' => 'handleFunction', + 'method' => 'handleMethod', + 'var' => 'handleVar', + 'const' => 'handleConst', + 'packagepage' => 'handlePackagePage', + 'include' => 'handleInclude', + 'global' => 'handleGlobal', + 'tutorial' => 'handleTutorial', + ); + + /** + * $data contains parsed structures for the current page being parsed + * + * In version 1.1+, $data is only used to store the current page information. + * All handling of documented elements is handled by the + * {@link ProceduralPages} and {@link Classes} classes. + * @var parserData + */ + var $data; + + /** + * set in {@link Setup.inc.php} to the value of the quitemode commandline + * option. + * + * If this option is true, informative output while parsing will not be + * displayed (documentation is unaffected) + * @var boolean + * @tutorial phpDocumentor.howto.pkg#using.command-line.quiet + */ + var $quietMode = false; + + /** + * used to keep track of inheritance at the smartest level possible for a + * dumb computer + * @var Classes + */ + var $classes = false; + + /** + * used to keep track of all elements in a procedural page. Handles name + * conflicts with elegance + * @since 1.1 + * @var ProceduralPages + */ + var $proceduralpages = false; + + /** + * an array of template names indexed by converter name + * + * For example, if the default HTMLframesConverter is using the DOM/l0l33t + * template, the array will be + * $converters['frames'] = 'DOM/l0l33t' + * @var array Format: array(Convertername1 => templatename) + * @see Converter + */ + var $converters = false; + /** + * @var string Title of generated documentation, passed to Converters + */ + var $title = ''; + + var $uses = array(); + + var $db_template; + + /** + * Stores parsed CHANGELOG/INSTALL/README files + * @var array Format: array(CHANGELOG => contents, + * INSTALL => contents, + * README => contents) + */ + var $ric = array(); + + /** + * Flag used to determine whether the last docblock + * was a page-level docblock. + * @var boolean + * @access private + */ + var $_lastDocBlockWasPageLevel = false; + + /** + * Flag used to determine whether the Page-level + * DocBlock was declared in old or new style + * @var boolean + * @access private + */ + var $_oldPageLevel = false; + + /** + * sets up basic data structures + * @param string Title of generated documentation, passed to Converters + * @see $title, $data, $classes, $proceduralpages + */ + function phpDocumentor_IntermediateParser($title='Generated Documentation') + { + $this->title = $title; + $this->data = new parserData; + $this->classes = new Classes; + $this->proceduralpages = new ProceduralPages; + } + + /** + * Retrieve the relative path. If the path contains "pear/" it will + * be used as the base, otherwise the Program_Root string will be used. + * @global array uses 'Program_Root' option to replace it with '' for + * retrieving the source location of a file + * @param string path to file + * @return string + * @see $sourceLocation + * @access private + */ + function _getSourceLocation($sl, $sourceloc) + { + global $_phpDocumentor_options; + if (empty($sl)) return false; + $sl = str_replace('\\','/',$sl); + if (strpos($sl,'pear/')) + { + $sl = substr($sl,strpos($sl,'pear/') + 5); + if (dirname($sl) == '.') + { + return 'PEAR'; + } + return dirname($sl); + } else + { + if (strpos(str_replace($_phpDocumentor_options['Program_Root'] . PATH_DELIMITER,'',$sourceloc),PATH_DELIMITER) === false) + return ''; + return dirname(str_replace($_phpDocumentor_options['Program_Root'] . PATH_DELIMITER,'',$sourceloc)); + } + } + + /** + * Guess the package/subpackage based on subdirectory if the --pear option + * + * A file in pear/dir/file.php will be in package "dir." A file in + * pear/dir/subdir/file.php will be in package "dir," subpackage "subdir." + * @param string full path of file + * @param template-ready source location Program_Root/dir/file.php + * @global array uses the 'pear' option to determine whether to guess based + * on subdirectory + * @tutorial phpDocumentor.howto.pkg#using.command-line.pear + */ + function _guessPackage($path, $sourceloc) + { + global $_phpDocumentor_setting; + if ($_phpDocumentor_setting['pear']) + { + $subpath = explode(PATH_DELIMITER, $this->_getSourceLocation($path, $sourceloc)); + if (!empty($subpath[0])) + { // can only have package and subpackage in this version + $package = $subpath[0]; + $subpackage = ''; + if (isset($subpath[1])) $subpackage = $subpath[1]; + return array($package,$subpackage); + } else return array($this->package, $this->subpackage); + } else return array($this->package, $this->subpackage); + } + + /** + * handles post-parsing of include/require/include_once/include_once + * + * This function sets {@link $data}->clean to false to tell the + * phpDocumentor_IntermediateParser that a page-level DocBlock can't be + * found after this point on this page. It then sets the package + * to be the same as the page, and adds itself to the + * {@link ProceduralPages} class + * @param integer $event Event number from {@link Parser.inc} + * @param parserInclude $data + */ + function handleInclude($event,$data) + { + if ($this->_lastDocBlockWasPageLevel) + { + addWarning(PDERROR_DOCBLOCK_CONFLICT, $data->getName(), $data->getFile()); + if (!$this->_oldPageLevel) + { + unset($this->last); + } + } + $this->_lastDocBlockWasPageLevel = + $this->data->clean = false; + // page was @ignored + if ($this->private_page) + { + unset($this->last); + return; + } + if (empty($this->last)) + { + if (isset($this->db_template)) + // use the docblock template + $this->last = phpDocumentor_clone($this->db_template); + else + // we don't have a docblock, create an empty one to get rid of errors + $this->last = new parserDocblock(); + } +// $this->last->setLineNumber($data->getLineNumber()); + if ($this->last->getKeyword('ignore')) + { + $this->last = false; + return; +// addWarning(PDERROR_IGNORE_TAG_IGNORED,'include',$data->getName().'('.$data->getValue().')'); + } + + $this->last->overridePackage($this->category,$this->package,$this->subpackage,$data->getName(),'include'); + $data->setDocBlock($this->last); + $this->proceduralpages->addInclude($data); + $this->last = false; + } + + /** + * handles post-parsing of global variables + * + * This function sets {@link $data}->clean to false to tell the + * phpDocumentor_IntermediateParser that a page-level DocBlock can't be + * found after this point on this page. It then sets the package + * to be the same as the page, and adds itself to the + * {@link ProceduralPages} class + * @param integer $event Event number from {@link Parser.inc} + * @param parserGlobal $data + */ + function handleGlobal($event,$data) + { + if ($this->_lastDocBlockWasPageLevel) + { + addWarning(PDERROR_DOCBLOCK_CONFLICT, 'global variable', $data->getName()); + if (!$this->_oldPageLevel) + { + unset($this->last); + } + } + $this->_lastDocBlockWasPageLevel = + $this->data->clean = false; + if ($this->private_page) + { + unset($this->last); + return; + } + if (empty($this->last)) + { + if (isset($this->db_template)) + // use the docblock template + $this->last = phpDocumentor_clone($this->db_template); + else + // we don't have a docblock, create an empty one to get rid of errors + $this->last = new parserDocblock(); + } +// $this->last->setLineNumber($data->getLineNumber()); + if ($this->last->getKeyword('ignore')) + { + addWarning(PDERROR_IGNORE_TAG_IGNORED,'global variable - just don\'t document the',$data->getName()); + $this->last = false; + return; + } + $this->last->overridePackage($this->category,$this->package,$this->subpackage,$data->getName(),'global'); + $data->setDocBlock($this->last); + if ($data->docblock->getKeyword('name')) + { + $a = $data->docblock->getKeyword('name'); + if (is_object($a)) $a = $a->value; + $data->setName($a); + } + $this->proceduralpages->addGlobal($data); + $this->last = false; + } + + /** + * handles post-parsing of Package-level documentation pages. + * + * sets the {@link $package_pages}[$data->package] to $data + * @param integer $event Event number from {@link Parser.inc} + * @param parserPackagePage $data + */ + function handlePackagePage($event,$data) + { + $this->package_pages[$data->package] = &$data; + $this->last = false; + } + + /** + * handle post-parsing of Tutorials. + * + * This adds the parsed tutorial to the tutorial tree + * @uses $tutorials sets the value of tutorials to parameter $data + * @param integer $event Event Number + * @param parserTutorial $data + * @since 1.2 + */ + function handleTutorial($event,$data) + { + if (isset($this->packagecategories[$data->package])) + { + $data->category = $this->packagecategories[$data->package]; + } else + { + $data->category = $GLOBALS['phpDocumentor_DefaultCategoryName']; + } + $this->tutorials[$data->package][$data->subpackage][$data->tutorial_type][$data->name] = $data; + } + + /** + * handles post-parsing of class vars + * + * This function sets up a @var tag if none is found, and aligns $data's + * $path var and packages to match the parent object + * @param integer $event Event number from {@link Parser.inc} + * @param parserVar $data + */ + function handleVar($event,$data) + { + global $_phpDocumentor_setting; + if ($this->private_class) + { + unset($this->last); + return; + } + if (empty($this->last)) + { + if (isset($this->db_template)) + { + // use the docblock template + $this->last = phpDocumentor_clone($this->db_template); + } else { + // we don't have a docblock, create an empty one to get rid of errors + $this->last = new parserDocblock(); + } + } +// $this->last->setLineNumber($data->getLineNumber()); + $this->last->overridePackage($this->category,$this->package,$this->subpackage,$data->getName(),'var'); + $this->last->updateModifiers($data->getModifiers()); + + if ($this->last->getKeyword('ignore')) + { + $this->last = false; + return; +// addWarning(PDERROR_IGNORE_TAG_IGNORED,'var',$this->cur_class.'::'.$data->getName()); + } + if (!$this->last->var) + { + $this->last->addVar('mixed',new parserStringWithInlineTags); + } + + if ($_phpDocumentor_setting['pear']) + { + if (strpos($data->getName(), '_') == 1 && !$this->last->getKeyword('access')) + { + addWarning(PDERROR_PRIVATE_ASSUMED,'class variable',$data->class.'::'.$data->getName()); + $this->last->addKeyword('access','private'); + $data->setDocBlock($this->last); + } + } + $data->setDocBlock($this->last); + $data->path = $this->data->parent->path; + $this->classes->addVar($data); + $this->last = false; + } + + /** + * handles post-parsing of class constants + * + * This function aligns $data's + * $path var and packages to match the parent object + * @param integer $event Event number from {@link Parser.inc} + * @param parserVar $data + */ + function handleConst($event,$data) + { + global $_phpDocumentor_setting; + if ($this->private_class) + { + unset($this->last); + return; + } + if (empty($this->last)) + { + if (isset($this->db_template)) + // use the docblock template + $this->last = phpDocumentor_clone($this->db_template); + else + // we don't have a docblock, create an empty one to get rid of errors + $this->last = new parserDocblock(); + } +// $this->last->setLineNumber($data->getLineNumber()); + $this->last->overridePackage($this->category,$this->package,$this->subpackage,$data->getName(),'const'); + + if ($this->last->getKeyword('ignore')) + { + $this->last = false; + return; +// addWarning(PDERROR_IGNORE_TAG_IGNORED,'var',$this->cur_class.'::'.$data->getName()); + } + $data->setDocBlock($this->last); + $data->path = $this->data->parent->path; + $this->classes->addConst($data); + $this->last = false; + } + + /** + * handles post-parsing of class methods + * + * This function first aligns $data's path and package to match the parent + * object, and also aligns the docblock's @param, @global, and @staticvar + * tags with the information parsed from the method source code. It also + * checks to see if the method is a constructor and sets the $isConstructor + * flag. If source code has been parsed by a {@}source} tag, the source is + * added to its docblock + * + * Finally, it adds the method to the {@link Classes} class. + * @param integer $event Event number from {@link Parser.inc} + * @param parserMethod $data + */ + function handleMethod($event,$data) + { + global $_phpDocumentor_setting; + if ($this->private_class) + { + unset($this->last); + return; + } + + if (empty($this->last)) + { + if (isset($this->db_template)) + // use the docblock template + $this->last = phpDocumentor_clone($this->db_template); + else + // we don't have a docblock, create an empty one to get rid of errors + $this->last = new parserDocblock(); + } +// $this->last->setLineNumber($data->getLineNumber()); + if ($this->last->getKeyword('ignore')) + { + $this->last = false; + return; +// addWarning(PDERROR_IGNORE_TAG_IGNORED,'method',$this->cur_class.'::'.$data->getName()); + } + $this->last->overridePackage($this->category,$this->package,$this->subpackage,$data->getName(),'method'); + if ($data->hasSource()) + { + $this->last->setSource($data->getSource(), $data->getClass()); + } + foreach($data->listParams() as $param) + { + $update_params[] = $param[0]; + } + foreach($data->listGlobals() as $param) + { + $update_globals[] = $param[1]; + } + foreach($data->listStatics() as $param) + { + $update_statics[] = $param[0]; + } + if (isset($update_params)) + $this->last->updateParams($update_params); + if (isset($update_globals)) + $this->last->updateGlobals($update_globals); + if (isset($update_statics)) + $this->last->updateStatics($update_statics); + $this->last->updateModifiers($data->getModifiers()); + unset($update_params); + unset($update_globals); + unset($update_statics); + + if ($data->getName() == $this->cur_class) $data->setConstructor(); + if ($data->getName() == '__construct') { + $data->setConstructor(); + } + if ($data->getName() == '__destruct') { + $data->setDestructor(); + } + + if ($_phpDocumentor_setting['pear']) + { + if (strpos($data->getName(), '_') === 0 && substr($data->getName(), 1) == $data->class) + { // is destructor + $data->setDestructor(); + } elseif (strpos($data->getName(), '_') === 0 && !$this->last->getKeyword('access')) + { + if (strpos($data->getName(), '__') !== 0) { + addWarning(PDERROR_PRIVATE_ASSUMED,'method',$data->class.'::'.$data->getName().'()'); + $this->last->addKeyword('access','private'); + $data->setDocBlock($this->last); + } + } + } + $data->setDocBlock($this->last); + $data->path = $this->data->parent->path; + $this->classes->addMethod($data); + $this->last = false; + } + + /** + * handles post-parsing of functions + * + * This function sets {@link $data}->clean to false to tell the + * phpDocumentor_IntermediateParser that a page-level DocBlock can't be + * found after this point on this page. It then sets the package to be the + * same as the page, aligns the docblock's @param, @global, and @staticvar + * tags with the information parsed from the function source code. + * + * If source code has been parsed by a {@}source} tag, the source is added + * to its docblock, and then the parserFunction adds itself to the + * {@link ProceduralPages} class + * @param integer $event Event number from {@link Parser.inc} + * @param parserFunction $data + */ + function handleFunction($event,$data) + { + if ($this->_lastDocBlockWasPageLevel) + { + addWarning(PDERROR_DOCBLOCK_CONFLICT, 'function', $data->getName()); + if (!$this->_oldPageLevel) + { + unset($this->last); + } + } + $this->_lastDocBlockWasPageLevel = + $this->data->clean = false; + if ($this->private_page) + { + unset($this->last); + return; + } + + if (empty($this->last)) + { + if (isset($this->db_template)) + // use the docblock template + $this->last = phpDocumentor_clone($this->db_template); + else + // we don't have a docblock, create an empty one to get rid of errors + $this->last = new parserDocblock(); + } +// $this->last->setLineNumber($data->getLineNumber()); + if ($this->last->getKeyword('ignore')) + { + unset($this->last); + return; + } + $this->last->overridePackage($this->category,$this->package,$this->subpackage,$data->getName(),'function'); + + foreach($data->listParams() as $param) + { + $update_params[] = $param[0]; + } + foreach($data->listGlobals() as $param) + { + $update_globals[] = $param[1]; + } + foreach($data->listStatics() as $param) + { + $update_statics[] = $param[0]; + } + if (isset($update_params)) + $this->last->updateParams($update_params); + if (isset($update_globals)) + $this->last->updateGlobals($update_globals); + if (isset($update_statics)) + $this->last->updateStatics($update_statics); + unset($update_params); + unset($update_globals); + unset($update_statics); + + if ($data->hasSource()) + { + $this->last->setSource($data->getSource()); + } + if (count($this->last->params) == 1 && !count($data->listParams())) + { + // if the function has no parameters, and 1 @param, add it to the list as optional, default value is description from @param + $pars = $this->last->listParams(); + $data->addParam($pars[0]['var'],$pars[0]['data']->getString()); + } + $data->setDocBlock($this->last); + $this->proceduralpages->addFunction($data); + $this->last = false; + } + + /** + * handles post-parsing of defines + * + * This function sets {@link $data}->clean to false to tell the + * phpDocumentor_IntermediateParser that a page-level DocBlock can't be + * found after this point on this page. It then sets the package to be the + * same as the page and adds itself to the {@link ProceduralPages} class + * @param integer $event Event number from {@link Parser.inc} + * @param parserDefine $data + */ + function handleDefine($event,$data) + { + if ($this->_lastDocBlockWasPageLevel) + { + addWarning(PDERROR_DOCBLOCK_CONFLICT, 'define', $data->getName()); + if (!$this->_oldPageLevel) + { + unset($this->last); + } + } + $this->_lastDocBlockWasPageLevel = + $this->data->clean = false; + if ($this->private_page) + { + unset($this->last); + return; + } + if (empty($this->last)) + { + if (isset($this->db_template)) + // use the docblock template + $this->last = phpDocumentor_clone($this->db_template); + else + // we don't have a docblock, create an empty one to get rid of errors + $this->last = new parserDocblock(); + } +// $this->last->setLineNumber($data->getLineNumber()); + if ($this->last->getKeyword('ignore')) + { + unset($this->last); + return; + } + + $this->last->overridePackage($this->category,$this->package,$this->subpackage,$data->getName(),'define'); + $data->setDocBlock($this->last); + $this->proceduralpages->addDefine($data); + $this->last = false; + } + + /** + * handles post-parsing of classes + * + * This function sets {@link $data}->clean to false to tell the + * phpDocumentor_IntermediateParser that a page-level DocBlock can't be + * found after this point on this page. It sets {@link $cur_class} to its + * name, and if an @ignore tag is found in the DocBlock, it sets + * {@link $private_class} to true, to prevent post-parsing of any of the + * class's vars or methods. Then it checks for the existence of a package + * page for the class's package + * @param integer $event Event number from {@link Parser.inc} + * @param parserClass $data + */ + function handleClass($event,$data) + { + global $_phpDocumentor_setting; + if ($this->_lastDocBlockWasPageLevel) + { + if (!$this->_oldPageLevel) + { + addWarning(PDERROR_DOCBLOCK_GOES_CLASS, $data->getName()); + $doc = new parserDocBlock; + $doc->category = $this->category; + $doc->package = $this->package; + $doc->subpackage = $this->subpackage; + if ($_phpDocumentor_setting['sourcecode']) { + $doc->canSource(); + $doc->addFileSource($this->data->parent->path, $this->data->parent->source); + } + $this->data->setDocBlock($doc); + unset($doc); + $this->last->cantSource(); + } + } + $this->_lastDocBlockWasPageLevel = + $this->data->clean = false; + if (empty($this->last)) + { + if (isset($this->db_template)) + // use the docblock template + $this->last = phpDocumentor_clone($this->db_template); + else + // we don't have a docblock, create an empty one to get rid of errors + $this->last = new parserDocblock(); + list($this->last->package, $this->last->subpackage) = $this->_guessPackage($this->data->parent->path, $this->data->parent->getSourceLocation('dummy')); + addWarning(PDERROR_NO_PACKAGE_TAG,'class',$data->getName(),$this->last->package); + } else + { + if (!$this->last->getExplicitPackage()) + { + list($this->last->package, $this->last->subpackage) = $this->_guessPackage($this->data->parent->path, $this->data->parent->getSourceLocation('dummy')); + addWarning(PDERROR_NO_PACKAGE_TAG,'class',$data->getName(),$this->last->package); + } else + { + if (isset($this->packagecategories[$this->package]) + && $this->packagecategories[$this->package] != $this->category) + addWarning(PDERROR_PACKAGECAT_SET,$this->package, + $this->packagecategories[$this->package], + $this->category); + $this->packagecategories[$this->package] = $this->category; + } + } + $this->last->updateModifiers($data->getModifiers()); +// $this->last->setLineNumber($data->getLineNumber()); + $data->setDocBlock($this->last); + $this->cur_class = $name = $data->getName(); + if ($this->last->getKeyword('ignore')) + { + $this->private_class = true; + unset($this->last); + return; + } + $data->path = $this->data->parent->path; + $this->classes->addClass($data); + $this->private_class = false; + if ($this->last->package) + { + $this->parsePackagePage($this->last->package, $this->data->parent->getPath()); + } + $this->last = false; + } + + /** + * handles post-parsing of procedural pages + * + * this event is called at the start of a new page, before the Parser knows + * whether the page will contain any procedural pages or not + * @param integer $event Event number from {@link Parser.inc} + * @param parserPage $data + */ + function handlePage($event,$data) + { + $type = 'page'; + $this->private_page = false; + $this->data = new parserData; + $data->category = $this->category = $GLOBALS['phpDocumentor_DefaultCategoryName']; + $this->package = $GLOBALS['phpDocumentor_DefaultPackageName']; + $this->subpackage = ''; + $this->proceduralpages->addPage($data); + $this->data->setParent($data); + $this->pages[$data->getPath()] = $this->data; + $this->classes->nextFile($data->getPath()); + $this->packageoutput = $data->getPackageOutput(); + } + + /** + * handles post-parsing of DocBlocks + * + * This function sets {@link $last} to the DocBlock represented by $data, to + * allow the next documentable element passed to + * phpDocumentor_IntermediateParser to link the DocBlock into its $docblock + * property. This function also checks for two special cases of DocBlocks: + *
              + *
            1. First DocBlock in the file contains a @package tag
            2. + *
            3. First DocBlock in the file is immediately followed by another + * DocBlock
            4. + *
            + * In both cases, the function extracts this tag and uses it as the + * page-level package. If the @package tag is in the DocBlock of an + * element (function, global variable, whatever) that isn't a page-level + * DocBlock, a warning will be raised to notify the author that a @package + * tag belongs in a page-level DocBlock. + * + * New in version 1.2.2, if the first DocBlock in a file contains + * a @package tag, it is a page-level DocBlock. + * + * If the DocBlock is page-level, it is processed with + * {@link _processPageLevelDocBlock} + * + * Finally, the function replaces the old parserPage in + * {@link parserData::$data}->parent with the new one containing information + * from the DocBlock by calling {@link addPage()}, and checks for + * package-level docs. + * @param integer $event Event number from {@link Parser.inc} + * @param parserDocBlock $data + */ + function handleDocBlock($event,$data) + { + $type = 'docblock'; + $data->postProcess(); + // Zend desc support + if ($tdesc = $data->getKeyword('desc')) + { + $data->setShortDesc($tdesc); + unset($data->tags['desc']); + } + $this->_lastDocBlockWasPageLevel = false; + // 1st docblock in file, check for @package + if ($this->data->isClean() && !isset($this->last)) + { + if ($data->getExplicitPackage()) + { + // new with 1.2.2: + // if the first docblock in a file + // contains a @package tag, then it is + // a page-level docblock + $this->_processPageLevelDocBlock($data); + $this->_lastDocBlockWasPageLevel = true; + $this->all_packages[$data->package] = 1; + $this->last = $data; + return; + } + $doc = new parserDocBlock; + $doc->category = $this->category; + $doc->package = $this->package; + $doc->subpackage = $this->subpackage; + $this->data->setDocBlock($doc); + $this->proceduralpages->addPagePackage($this->data->parent->getPath(),$this->package,$this->subpackage); + unset($doc); + } + // 2nd docblock in a row, and it's at the top of the file, page-level docblock + if ($this->lasttype == "docblock" && $this->data->isClean()) + { + $this->_processPageLevelDocBlock($this->last); + $this->_oldPageLevel = true; + $this->_lastDocBlockWasPageLevel = false; + } + $this->all_packages[$data->package] = 1; + $this->last = $data; + } + + /** + * Process a Page-level DocBlock + * + * First, it checks for an @ignore tag, + * and if found, calls {@link ProceduralPages::ignorePage()}. An @ignore + * tag in a page-level DocBlock will ignore all functions, defines, global + * variables, and includes. It will not ignore classes! The function next + * checks for an @access private, and if --parseprivate is off, performs the + * same actions as @ignore, raising a warning for the unsuspecting user. + * Next, it checks for the @name tag, which is used to rename the page. + * This is also a PEAR compatibility issue, and may not be very useful in + * the long run. Documentation is best when it refers to real entities in + * the package, and not to aliases. + * @access private + */ + function _processPageLevelDocBlock($data) + { + global $_phpDocumentor_setting; + // can only have 1 package-level docblock, others are ignored + if (!$this->data->isClean()) + { + return; + } + $this->data->clean = false; + $this->data->explicitDocBlock(); + $data->canSource(); + if ($_phpDocumentor_setting['sourcecode']) + { + $data->addFileSource($this->data->parent->path, $this->data->parent->source); + } + if (!$data->getExplicitPackage()) + { + list($data->package,$data->subpackage) = $this->_guessPackage($this->data->parent->getPath(), $this->data->parent->getSourceLocation('dummy')); + addWarning(PDERROR_NO_PACKAGE_TAG,'file',$this->data->parent->getPath(),$this->last->package); + } + if (isset($this->packagecategories[$this->package]) + && $this->packagecategories[$this->package] != $this->category) + addWarning(PDERROR_PACKAGECAT_SET,$this->package, + $this->packagecategories[$this->package], + $data->category); + $this->packagecategories[$this->package] = $data->category; + $this->category = $this->data->parent->category = $data->category; + $this->packagecategories[$this->package] = $this->category; + $this->subpackage = $this->data->parent->subpackage = $data->subpackage; + if ($data->getKeyword('ignore')) + { + $this->proceduralpages->ignorePage($this->data->parent); + $this->private_page = true; + unset($this->last); + $this->privatepages[$this->data->parent->getPath()] = $this->data; + unset($this->pages[$this->data->parent->getPath()]); + return; + } + $this->data->setDocBlock($data); + $this->package = $this->data->parent->package = $data->package; + $this->subpackage = $this->data->parent->subpackage = $data->subpackage; + $this->proceduralpages->addPagePackage($this->data->parent->getPath(),$this->package,$this->subpackage); + if ($access = $data->getKeyword('access')) + { + if (is_object($access) && ($access->getString() == 'private') && (!$this->parsePrivate)) + { + addWarning(PDERROR_PARSEPRIVATE, $this->data->parent->getPath()); + $this->proceduralpages->ignorePage($this->data->parent); + $this->private_page = true; + unset($this->last); + $this->privatepages[$this->data->parent->getPath()] = $this->data; + unset($this->pages[$this->data->parent->getPath()]); + return; + } + } + if ($data->getKeyword('name')) + { + $a = $data->getKeyword('name'); + if (is_object($a)) $a = $a->value; + $this->data->parent->setFile($a); + $this->proceduralpages->setName($a); + } + $this->addPage($this->data->parent, $this->data->parent->getPath()); + if ($this->package) + { + $this->parsePackagePage($this->package, $this->data->parent->getPath()); + } + } + + /** + * Backward-compatibility only, use the new tutorials for more power + * @tutorial tutorials.pkg + * @param string package name of package file to parse + * @param string directory of file that contains package name + */ + function parsePackagePage($package, $path) + { + if (!isset($this->package_pages[$package])) + { + if (file_exists(dirname($path) . SMART_PATH_DELIMITER . $package . '.html')) + { + if ($this->quietMode === false) + { + phpDocumentor_out("Reading package-level file ".$package . '.html'); + flush(); + } + $fp = fopen(dirname($path) . SMART_PATH_DELIMITER . $package . '.html',"r"); + $ret = fread($fp,filesize(dirname($path) . SMART_PATH_DELIMITER . $package . '.html')); + fclose($fp); + unset($fp); + if ($this->quietMode === false) + { + phpDocumentor_out(" -- Parsing File\n"); + flush(); + } + $pageParser = new ppageParser; + $tempp = $this->package; + $lp = $this->last; + $pageParser->subscribe('*',$this); + $pageParser->parse($ret,false,$package); + $this->package = $tempp; + $this->last = $lp; + unset($tempp); + unset($pageParser); + } + } + } + + /** + * called via {@link Parser::parse()} and Parser's inherited method + * {@link Publisher::publishEvent()} + * + * $event is one of the PHPDOC constants from Parser.inc. If it is not + * PHPDOCUMENTOR_EVENT_NEWSTATE, then a function name is retrieved from the + * {@link $event_handlers} array and called to handle the $data + * @param integer $event event number from {@link Parser.inc} + * @param mixed $data if $event is {@link PHPDOCUMENTOR_EVENT_NEWSTATE}, $data is a {@link PHP_DOC_EVENT_END_PAGE} or {@link STATE_END_CLASS}, + * otherwise $data is either a {@link parserDocBlock}, {@link parserPage} or descendant of {@link parserElement} + * @global array we use 'sourcecode' to determine whether to highlight the source + * of the current file if it has no file-level docblock + */ + function HandleEvent($event,$data) + { + global $_phpDocumentor_setting; + global $phpDocumentor_DefaultPackageName, $phpDocumentor_DefaultCategoryName; + if (empty($this->packagecategories)) + $this->packagecategories[$phpDocumentor_DefaultPackageName] = $phpDocumentor_DefaultCategoryName; + if ($event == PHPDOCUMENTOR_EVENT_NEWSTATE) + { + if ($data == STATE_END_CLASS) + { + } elseif ($data == PHPDOCUMENTOR_EVENT_END_PAGE) + { + if (!$this->private_page) + { + $this->all_packages[$this->package] = 1; + if (!$this->data->hasExplicitDocBlock()) + { + $doc = $this->data->docblock; + if (!$this->data->docblock) + { + $doc = new parserDocBlock; + } + if ($_phpDocumentor_setting['sourcecode']) + { + $doc->canSource(); + $doc->addFileSource($this->data->parent->path, $this->data->parent->source); + } + list($doc->package,$doc->subpackage) = $this->_guessPackage($this->data->parent->getPath(), $this->data->parent->getSourceLocation('dummy')); + addWarning(PDERROR_NO_PAGE_LEVELDOCBLOCK,$this->data->parent->getPath()); + $this->data->setDocBlock($doc); + $this->proceduralpages->addPage($this->data->parent,$doc->package,$doc->subpackage); + } + $this->pages[$this->data->parent->getPath()] = $this->data; + } + $this->private_page = false; + $this->private_class = false; + if (isset($this->db_template)) + { + addWarning(PDERROR_DB_TEMPLATE_UNTERMINATED); + } + unset($this->db_template); + unset($this->last); + } elseif ($data == PHPDOCUMENTOR_EVENT_END_DOCBLOCK_TEMPLATE) + { + unset($this->db_template); + } + //echo $this->state_lookup[$data] . "\n"; + //echo $data."\n"; + } + else + { + if ($event == PHPDOCUMENTOR_EVENT_README_INSTALL_CHANGELOG) + { + $this->ric[$data[0]] = $data[1]; + return; + } + if ($event == PHPDOCUMENTOR_EVENT_DOCBLOCK_TEMPLATE) + { + $data->postProcess(); + $this->db_template = $data; + $this->_lastDocBlockWasPageLevel = false; + // 2nd docblock in a row, and it's at the top of the file, page-level docblock + if ($this->type == "docblock" && $this->data->isClean()) + { + // can only have 1 package-level docblock, others are ignored + $this->data->clean = false; + if ($this->last->getKeyword('ignore')) + { + $this->proceduralpages->ignorePage($this->data->parent); + $this->private_page = true; + unset($this->last); + $this->privatepages[$this->data->parent->getPath()] = $this->data; + unset($this->pages[$this->data->parent->getPath()]); + return; + } + $this->data->setDocBlock($this->last); + $this->package = $this->data->parent->package = $this->last->package; + $this->subpackage = $this->data->parent->subpackage = $this->last->subpackage; + $this->proceduralpages->addPagePackage($this->data->parent->getPath(),$this->package,$this->subpackage); + if ($access = $this->last->getKeyword('access')) + { + if (is_object($access) && ($access->getString() == 'private') && (!$this->parsePrivate)) + { + addWarning(PDERROR_PARSEPRIVATE, $this->data->parent->getPath()); + $this->proceduralpages->ignorePage($this->data->parent); + $this->private_page = true; + unset($this->last); + $this->privatepages[$this->data->parent->getPath()] = $this->data; + unset($this->pages[$this->data->parent->getPath()]); + return; + } + } + if ($this->last->getKeyword('name')) + { + $a = $this->last->getKeyword('name'); + if (is_object($a)) $a = $a->value; + $this->data->parent->setFile($a); + $this->proceduralpages->setName($a); + } + $this->addPage($this->data->parent, $this->data->parent->getPath()); + if ($this->package) + { + $this->parsePackagePage($this->package, $this->data->parent->getPath()); + } + } + unset($this->last); + } else + { + $this->lasttype = $this->type; + $type = $data->getType(); +// fancy_debug($type,$data); + if (($type != 'page') && ($type != 'docblock') && ($type != 'packagepage') && ($type != 'tutorial')) + { + $data->setFile($this->data->parent->getFile()); + } + $this->type = $type; + //echo $type . "\n"; + + if (isset($this->event_handlers[$type])) + { + $handle = $this->event_handlers[$type]; + $this->$handle($event,$data); + } + } + } + } + + /** + * Replaces the {@link parserPage} represented by $this->pages[$path] with + * $page + * + * Called by {@link addPageIfNecessary(), handleDocBlock()} and + * {@link ProceduralPages::setupPages()}, this method first checks to see if + * the page has been added. If not, it assumes that the page has either + * been @ignored or set with @access private with --parseprivate off, and + * returns {@link addPrivatePage()}. Otherwise, it sets the pages[$path] to + * be the parserPage $page and sets the package and subpackage to that of + * $page + * @see $pages + * @param parserPage + * @param string full path to the file + */ + function addPage($page, $path) + { + if (!isset($this->pages[$path])) return $this->addPrivatePage($page, $path); + $this->pages[$path]->setParent($page); + if ($page->package != $GLOBALS['phpDocumentor_DefaultPackageName']) + { + if (!$this->pages[$path]->docblock) + { + $docblock = new parserDocBlock; + $docblock->package = $page->package; + $docblock->subpackage = $page->subpackage; + $this->pages[$path]->docblock = $docblock; + } else + { + $this->pages[$path]->docblock->package = $page->package; + $this->pages[$path]->docblock->subpackage = $page->subpackage; + } + } + } + + /** + * add a new {@link parserPage} to the $pages array if none is found + * + * This method is used when a page has been @ignored or marked with @access + * private, and a public class is in the page (a class with no @access + * private in its DocBlock). The method first creates a new page in the + * {@link $pages} array and then copies path information, and calls + * {@link addPage()} to set up packages + * @param string full path of page + */ + function addPageIfNecessary($path, &$class) + { + global $_phpDocumentor_setting; + if (!$this->parsePrivate) + { + if (!isset($this->pages[$path])) + { + $this->pages[$path] = new parserData; + $this->pages[$path]->docblock = new parserDocBlock; + $this->pages[$path]->docblock->package = $this->privatepages[$path]->docblock->package; + $this->pages[$path]->docblock->subpackage = $this->privatepages[$path]->docblock->subpackage; + $par = $this->privatepages[$path]->parent; + $this->pages[$path]->setParent($par); + $this->proceduralpages->addPage($par); + } + } + if (isset($_phpDocumentor_setting['packageoutput'])) + $packages = explode(',',$_phpDocumentor_setting['packageoutput']); + if (isset($_phpDocumentor_setting['packageoutput']) && + $this->pages[$path]->parent->package != $class->docblock->package && + !in_array($this->pages[$path]->parent->package,$packages)) + { + $this->pages[$path]->parent->package = $class->docblock->package; + $this->addPage($this->pages[$path]->parent, $path); + $this->proceduralpages->addPage($this->pages[$path]->parent); + } + } + + /** + * Adds a {@link parserPage} element to the {@link parserData} element in + * $this->privatepages[$path] + * + * Performs a similar function to addPage, but adds to the + * {@link $privatePages} array + * @param parserPage $page + * @param string $path full path to the page + * @see addPage() + */ + function addPrivatePage($page, $path) + { + $this->privatepages[$path]->setParent($page); + if ($page->package != $GLOBALS['phpDocumentor_DefaultPackageName']) + { + if (!$this->privatepages[$path]->docblock) + { + $docblock = new parserDocBlock; + $docblock->package = $page->package; + $docblock->subpackage = $page->subpackage; + $this->privatepages[$path]->docblock = $docblock; + } else + { + $this->privatepages[$path]->docblock->package = $page->package; + $this->privatepages[$path]->docblock->subpackage = $page->subpackage; + } + } + } + + /** + * adds a processed descendant of {@link parserElement} to the {@link $pages} + * array or {@link $privatepages} array + * + * This function expects the page to exist in either $pages or $privatepages. It calls the + * {@link parserData::addElement()} method to add $element to the page. + * @param parserElement $element this will actually be a descendant of parserElement + * @param string $path + */ + function addElementToPage($element, $path) + { + if (isset($this->privatepages[$path])) + { + if (isset($this->pages[$path])) + { + if ($element->type == 'class' || $element->type == 'method' + || $element->type == 'var' || $element->type == 'const') + { + $this->pages[$path]->addElement($element); + } else + $this->privatepages[$path]->addElement($element); + } else + $this->privatepages[$path]->addElement($element); + } else + { + if (isset($this->pages[$path])) + { + $this->pages[$path]->addElement($element); + } + } + } + + /** + * Add all the @uses tags from $element to the $uses array so that @usedby + * virtual tags can be added + * @uses parserUsesTag::getSeeElement() used to initialize {@link $uses} + * @uses parserUsesTag::getDescription() used to initialize {@link $uses} + * @param parserElement descendant of parserElement + * @param string full path to the file + */ + function addUses($element, $path) + { + if ($element->type == 'page') + { + $element = $this->pages[$element->path]; + } + if (!$this->parsePrivate && $element->docblock->hasaccess) + { + $a = $element->docblock->getKeyword('access'); + if (is_object($a) && $a->getString() == 'private') return; + } + if (isset($this->privatepages[$path])) + { + if (isset($this->pages[$path])) + { +// if ($element->type == 'function' || $element->type == 'method') + { + $uses = $element->docblock->getKeyword('uses'); + if ($uses) + { + if (!is_array($uses)) $uses = array($uses); + foreach($uses as $use) + { + if (!is_object($use)) continue; + $el = $use->getSeeElement(); + $description = $use->getDescription(); + $this->uses[$el][] = array($element, $description); + } + } + } + } + } else + { + if (isset($this->pages[$path])) + { +// if ($element->type == 'function' || $element->type == 'method') + { + $uses = $element->docblock->getKeyword('uses'); + if ($uses) + { + if (!is_array($uses)) $uses = array($uses); + foreach($uses as $use) + { + if (!is_object($use)) continue; + $el = $use->getSeeElement(); + $description = $use->getDescription(); + $this->uses[$el][] = array($element, $description); + } + } + } + } + } + } + + /** + * Add a {@link parserUsedByTag} link to every element referred to by @uses + * @param Converter temporary converter used to retrieve abstract links + * @uses phpDocumentor_IntermediateParser::addUses() indirectly, as + * addUses() sets up $uses, which is iterated over here + * @uses $pages sets up all @usedby tags from here + * @access private + */ + function _setupUsesList(&$converter) + { + ob_start(); + $converter->_createPkgElements($this->pages); + ob_end_clean(); + foreach($this->uses as $link => $elements) + { + foreach($elements as $element) + { + if ($element[0]->type == 'method' || $element[0]->type == 'var' || + $element[0]->type == 'const') + { + $converter->class = $element[0]->getClass(); + } + if ($element[0]->type == 'class') + { + $converter->class = $element[0]->getName(); + } + $reallink = $converter->getLink($link,$element[0]->docblock->package); + if (is_object($reallink)) + { + // add a used by tag to the docblock of the destination + switch(phpDocumentor_get_class($reallink)) + { + case 'pagelink' : + case 'functionlink' : + case 'definelink' : + case 'globallink' : + if (isset($this->pages[$reallink->path])) + { + for ($i=0;$ipages[$reallink->path]->elements);$i++) + { + if ($this->pages[$reallink->path]->elements[$i]->type == str_replace('link','',phpDocumentor_get_class($reallink)) && $this->pages[$reallink->path]->elements[$i]->getName() == $reallink->name) + { + $this->pages[$reallink->path]->elements[$i]->docblock->addUsedBy($element[0]->getLink($converter,false,true), $element[1]); +// debug('added @usedby to '.str_replace('link','',phpDocumentor_get_class($reallink)).' '.$reallink->name); + } + } + } + break; + case 'classlink' : + case 'methodlink' : + case 'varlink' : + case 'constlink' : + if (isset($this->pages[$reallink->path])) + { + for ($i=0;$ipages[$reallink->path]->classelements);$i++) + { + if ($this->pages[$reallink->path]->classelements[$i]->type == str_replace('link','',phpDocumentor_get_class($reallink)) && $this->pages[$reallink->path]->classelements[$i]->getName() == $reallink->name) + { + $this->pages[$reallink->path]->classelements[$i]->docblock->addUsedBy($element[0]->getLink($converter,false,true), $element[1]); +// debug('added @usedby to '.str_replace('link','',phpDocumentor_get_class($reallink)).' '.$reallink->name); + } + } + } + break; + } + } + } + } + } + + /** + * Interface to the Converter + * + * This function simply passes {@link $pages} and {@link package_pages} to + * the walk() method, and then calls the Output() method. Note that + * Output() is not required to do anything, and in fact doesn't in + * HTMLframesConverter. + * @uses Converter::walk() passes {@link $pages} and {@link $package_pages} + * @uses Converter::Output() + */ + function Convert($title, $converter) + { + $converter->walk($this->pages, $this->package_pages); + $converter->Output($title); + } + + /** + * Clean up classes + * + * {@source} + * @access private + * @uses Classes::Inherit() passes $this + */ + function fixClasses() + { + $this->classes->Inherit($this); + } + + /** + * Clean up Procedural Pages + * {@source} + * @access private + * @uses ProceduralPages::setupPages() passes $this + */ + function fixProcPages() + { + $this->proceduralpages->setupPages($this); + } + + /** + * If the parent class of $class is in a different package, adds it to the + * {@link $package_parents} array + * @param parserClass &$class + */ + function addPackageParent(&$class) + { + if (!is_array($class->parent)) return; + $par = $this->classes->getClass($class->parent[1], $class->parent[0]); + if ($class->docblock->package == $par->docblock->package) return; + $this->package_parents[$class->docblock->package] = $par->docblock->package; + if (!isset($this->package_parents[$par->docblock->package]) || !$this->package_parents[$par->docblock->package]) $this->package_parents[$par->docblock->package] = false; + } + + /** + * Add a converter name to use to the list of converters + * + * Sets up the {@link $converters} array. + * {@internal + * First, the Converter's file is included, and then, if successful, + * the converter classname is tested for existance. If all is good, + * then the templates are added to the list of converters/templates to use}} + * @param string $output output format (HTML, PDF, XML). Must be all caps + * @param string $name Converter name (frames, for example, is the name of + * HTMLframesConverter) + * @param string $template template to use, should be a relative path to the + * templates dir (like DOM/default) + */ + function addConverter($output,$name,$template) + { + if (strpos($name,PATH_DELIMITER)) + { + $parent = explode(PATH_DELIMITER,$name); + $parent = $parent[0]; + if ('@VER@' != '@'.'VER@') { + $filename = 'PhpDocumentor/phpDocumentor/Converters' . + PATH_DELIMITER . $output . PATH_DELIMITER . $parent . PATH_DELIMITER . $output . $parent . "Converter" . ".inc"; + if (Io::isIncludeable($filename)) + { + include_once($filename); + } + } else { + $filename = str_replace('\\','/',$GLOBALS['_phpDocumentor_install_dir']) . '/phpDocumentor/Converters' . + PATH_DELIMITER . $output . PATH_DELIMITER . $parent . PATH_DELIMITER . $output . $parent . "Converter" . ".inc"; + if (file_exists($filename) && is_readable($filename)) + { + include_once($filename); + } + } + if (!class_exists($output . $parent . 'Converter')) + { + addError(PDERROR_CONVERTER_NOT_FOUND,"parent Converter ".$output . $parent . "Converter of child Converter ".$output . str_replace(PATH_DELIMITER,'',$name) . "Converter"); + } + } + $filename = str_replace('\\', '/', $GLOBALS['_phpDocumentor_install_dir']) . '/phpDocumentor/Converters' . + PATH_DELIMITER . $output . PATH_DELIMITER . $name . PATH_DELIMITER . $output . + str_replace(PATH_DELIMITER, '', $name) . "Converter" . ".inc"; + if (file_exists($filename) && is_readable($filename)) + { + include_once($filename); + } + if (class_exists($output . str_replace(PATH_DELIMITER,'',$name) . 'Converter')) + { + $this->converters[$output][$output . str_replace(PATH_DELIMITER,'',$name) . "Converter"][] = $template; + } else + { + addError(PDERROR_CONVERTER_NOT_FOUND,$output . str_replace(PATH_DELIMITER,'',$name) . "Converter"); + } + } + + /** + * does a natural case sort on two {@link parserElement} descendants + * + * @param mixed $a + * @param mixed $b + * @return int + * @see generateElementIndex() + */ + function elementCmp ($a, $b) + { + return strnatcasecmp($a->getName(), $b->getName()); + } + + /** + * does a natural case sort on two class elements (either + * {@link parserClass, parserMethod} or {@link parserVar} + * + * @param mixed $a + * @param mixed $b + * @return int + * @see generateElementIndex() + */ + function ClasselementCmp ($a, $b) + { + if (phpDocumentor_get_class($a) == 'parserclass') $atest = $a->name; else $atest = $a->class; + if (phpDocumentor_get_class($b) == 'parserclass') $btest = $b->name; else $btest = $b->class; + + if(($c = strnatcasecmp($atest, $btest)) != 0) return $c; + if (phpDocumentor_get_class($a) != 'parserclass') $atest .= $a->name; + if (phpDocumentor_get_class($b) != 'parserclass') $btest .= $b->name; + if (phpDocumentor_get_class($a) == 'parsermethod' && phpDocumentor_get_class($b) == 'parsermethod') + { + if ($a->isConstructor) return -1; + if ($b->isConstructor) return 1; + if ($a->isDestructor) return -1; + if ($b->isDestructor) return 1; + } + return strnatcasecmp($atest,$btest); + } + + /** + * call this method once parsing has completed. + * + * This method calls the private methods fixClasses and fixProcPages, both + * of which adjust inheritance and package information based on complicated + * post-parsing rules described in {@link ProceduralPages::setupPages()} + * and {@link Classes::Inherit()}. Then, it sorts elements of the $pages + * array and calls Convert for each Converter in the $converters array + * @see $converters + * @see $pages + * @see Convert() + */ + function Output ($title = "Generated Documentation") + { + $GLOBALS['phpDocumentor_errors']->curfile = false; + $this->fixClasses(); + $this->fixProcPages(); +// var_dump($this->uses); +// exit; + phpDocumentor_out("\nSorting page elements..."); + flush(); + uasort($this->pages,'pagesort'); + foreach($this->pages as $i => $page) + { + usort($this->pages[$i]->elements,array($this,'elementCmp')); + usort($this->pages[$i]->classelements,array($this,'ClasselementCmp')); + } + phpDocumentor_out("done\n"); + flush(); + $complicatedout = false; + if (is_array($this->converters)) + { + if (count($this->converters) > 1) + { + $complicatedout = true; + } + phpDocumentor_out("Formatting @uses list..."); + flush(); + $a = new __dummyConverter($this->all_packages, $this->package_parents, $this->classes, $this->proceduralpages, $this->packageoutput, $this->parsePrivate, $this->quietMode, $this->targetDir , '', $this->title); + $this->_setupUsesList($a); + unset($a); + phpDocumentor_out("done\n\n"); + flush(); + foreach($this->converters as $converter => $blah) + { + if (is_array($blah)) + { + if (count($blah) > 1) + { + $complicatedout = true; + } + foreach($blah as $converter => $templates) + { + foreach($templates as $template) + { + $extraout = ''; + if ($complicatedout) + { + $extraout = SMART_PATH_DELIMITER . $converter; + } + if (count($templates) > 1) + { + $extraout .= SMART_PATH_DELIMITER . str_replace(PATH_DELIMITER, SMART_PATH_DELIMITER, substr($template,0,strlen($template) - 1)); + } + $a = new $converter($this->all_packages, $this->package_parents, $this->classes, $this->proceduralpages, $this->packageoutput, $this->parsePrivate, $this->quietMode, $this->targetDir . $extraout, $template, $this->title); + if (isset($this->templateBase)) + { + $a->setTemplateBase($this->templateBase, $template); + } + $a->ric = $this->ric; + $a->packagecategories = $this->packagecategories; + if (isset($this->tutorials)) $a->setTutorials($this->tutorials); + $this->Convert($title, $a); + unset($a); + } + } + } + } + } else + { + addErrorDie(PDERROR_NO_CONVERTERS); + } + } + + /** + * Sets the output directory + * + * @param string $dir the output directory + */ + function setTargetDir($dir) + { + $this->targetDir = $dir; + } + + /** + * Sets the template base directory + * + * @param string $dir the template base directory + * @tutorial phpDocumentor.howto.pkg#using.command-line.templatebase + */ + function setTemplateBase($dir) + { + $this->templateBase = $dir; + } + + /** + * set parsing information output mode (quiet or verbose) + * + * If set to false, no parsing information (parsing /php/file/thisfile.php, + * Converting etc.) will be displayed. + * Useful for cron jobs + * @param bool $quietMode + */ + function setQuietMode($quietMode) + { + $this->quietMode = $quietMode; + } + + /** + * set display of elements marked with @access private + * + * If set to true, elements will be displayed + * @param bool $parse + */ + function setParsePrivate($parse) + { + $this->parsePrivate = $parse; + } +} + +/** @access private */ +function pagesort($a, $b) +{ + return strnatcasecmp($a->parent->file,$b->parent->file); +} +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Io.inc b/buildscripts/PhpDocumentor/phpDocumentor/Io.inc new file mode 100644 index 00000000..0425096d --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Io.inc @@ -0,0 +1,868 @@ + + * @version $Id: Io.inc,v 1.5 2005/11/20 21:20:22 cellog Exp $ + * @package phpDocumentor + */ +/** + * Class to handle file and user io opperations + * + * @author Joshua Eichorn + * @version $Id: Io.inc,v 1.5 2005/11/20 21:20:22 cellog Exp $ + * @package phpDocumentor + */ +class Io +{ + + /** + * Holds all the options that are avaible to the cmd line interface + * and to the different web interfaces + */ + var $phpDocOptions; + /** + * Format: array(array(regexp-ready string to search for whole path, + * regexp-ready string to search for basename of ignore strings),...) + * @var false|array + */ + var $ignore = false; + + /** + * creates an array $this->phpDocOptions and sets program options in it. + * Array is in the format of: + *
            +     * [filename][tag][] = "f";
            +     * [filename][tag][] = "-file";
            +     * [filename][desc] "name of file to parse"
            +     * 
            + */ + function Io() + { + $this->phpDocOptions['filename']['tag'] = array( "-f", "--filename"); + $this->phpDocOptions['filename']['desc'] = "name of file(s) to parse ',' file1,file2. Can contain complete path and * ? wildcards"; + $this->phpDocOptions['filename']['type'] = "path"; + + $this->phpDocOptions['directory']['tag'] = array( "-d", "--directory"); + $this->phpDocOptions['directory']['desc'] = "name of a directory(s) to parse directory1,directory2"; + $this->phpDocOptions['directory']['type'] = "path"; + + $this->phpDocOptions['examplesdir']['tag'] = array( "-ed", "--examplesdir"); + $this->phpDocOptions['examplesdir']['desc'] = "full path of the directory to look for example files from @example tags"; + $this->phpDocOptions['examplesdir']['type'] = "path"; + + $this->phpDocOptions['templatebase']['tag'] = array( "-tb", "--templatebase"); + $this->phpDocOptions['templatebase']['desc'] = "base location of all templates for this parse."; + $this->phpDocOptions['templatebase']['type'] = "path"; + + $this->phpDocOptions['target']['tag'] = array("-t", "--target"); + $this->phpDocOptions['target']['desc'] = "path where to save the generated files"; + $this->phpDocOptions['target']['type'] = "path"; + + $this->phpDocOptions['ignore']['tag'] = array("-i", "--ignore"); + $this->phpDocOptions['ignore']['desc'] = "file(s) that will be ignored, multiple separated by ','. Wildcards * and ? are ok"; + $this->phpDocOptions['ignore']['type'] = "path"; + + $this->phpDocOptions['ignoretags']['tag'] = array("-it", "--ignore-tags"); + $this->phpDocOptions['ignoretags']['desc'] = "tags to ignore for this parse. @package, @subpackage, @access and @ignore may not be ignored."; + $this->phpDocOptions['ignoretags']['type'] = "value"; + + $this->phpDocOptions['hidden']['tag'] = array("-dh", "--hidden"); + $this->phpDocOptions['hidden']['desc'] = "set equal to on (-dh on) to descend into hidden directories (directories starting with '.'), default is off"; + $this->phpDocOptions['hidden']['type'] = "value"; + + $this->phpDocOptions['quiet']['tag'] = array("-q", "--quiet"); + $this->phpDocOptions['quiet']['desc'] = "do not display parsing/conversion messages. Useful for cron jobs on/off default off"; + $this->phpDocOptions['quiet']['type'] = "value"; + + $this->phpDocOptions['title']['tag'] = array("-ti","--title"); + $this->phpDocOptions['title']['desc'] = "title of generated documentation, default is 'Generated Documentation'"; + $this->phpDocOptions['title']['type'] = "value"; + + $this->phpDocOptions['help']['tag'] = array("-h", "--help"); + $this->phpDocOptions['help']['desc'] = " show this help message"; + + $this->phpDocOptions['useconfig']['tag'] = array("-c","--useconfig"); + $this->phpDocOptions['useconfig']['desc'] = "Use a Config file in the users/ subdirectory for all command-line options"; + $this->phpDocOptions['useconfig']['type'] = "value"; + + $this->phpDocOptions['parseprivate']['tag'] = array("-pp","--parseprivate"); + $this->phpDocOptions['parseprivate']['desc'] = "parse @internal and elements marked private with @access. Use on/off, default off"; + $this->phpDocOptions['parseprivate']['type'] = "value"; + + $this->phpDocOptions['packageoutput']['tag'] = array("-po","--packageoutput"); + $this->phpDocOptions['packageoutput']['desc'] = "output documentation only for selected packages. Use a comma-delimited list"; + $this->phpDocOptions['packageoutput']['type'] = "value"; + + $this->phpDocOptions['defaultpackagename']['tag'] = array("-dn","--defaultpackagename"); + $this->phpDocOptions['defaultpackagename']['desc'] = "name to use for the default package. If not specified, uses 'default'"; + $this->phpDocOptions['defaultpackagename']['type'] = "value"; + + $this->phpDocOptions['defaultcategoryname']['tag'] = array("-dc","--defaultcategoryname"); + $this->phpDocOptions['defaultcategoryname']['desc'] = "name to use for the default category. If not specified, uses 'default'"; + $this->phpDocOptions['defaultcategoryname']['type'] = "value"; + + $this->phpDocOptions['output']['tag'] = array("-o","--output"); + $this->phpDocOptions['output']['desc'] = "output information to use separated by ','. Format: output:converter:templatedir like \"HTML:frames:phpedit\""; + $this->phpDocOptions['output']['type'] = "value"; + + $this->phpDocOptions['converterparams']['tag'] = array("-cp","--converterparams"); + $this->phpDocOptions['converterparams']['desc'] = "dynamic parameters for a converter, separate values with commas"; + $this->phpDocOptions['converterparams']['type'] = "value"; + + $this->phpDocOptions['customtags']['tag'] = array("-ct","--customtags"); + $this->phpDocOptions['customtags']['desc'] = "custom tags, will be recognized and put in tags[] instead of unknowntags[]"; + $this->phpDocOptions['customtags']['type'] = "value"; + + $this->phpDocOptions['sourcecode']['tag'] = array("-s","--sourcecode"); + $this->phpDocOptions['sourcecode']['desc'] = "generate highlighted sourcecode for every parsed file (PHP 4.3.0+ only) on/off default off"; + $this->phpDocOptions['sourcecode']['type'] = "value"; + + $this->phpDocOptions['javadocdesc']['tag'] = array("-j","--javadocdesc"); + $this->phpDocOptions['javadocdesc']['desc'] = "JavaDoc-compliant description parsing. Use on/off, default off (more flexibility)"; + $this->phpDocOptions['javadocdesc']['type'] = "value"; + + $this->phpDocOptions['pear']['tag'] = array("-p","--pear"); + $this->phpDocOptions['pear']['desc'] = "Parse a PEAR-style repository (package is directory, _members are @access private) on/off default off"; + $this->phpDocOptions['pear']['type'] = "value"; + + $this->phpDocOptions['readmeinstallchangelog']['tag'] = array("-ric","--readmeinstallchangelog"); + $this->phpDocOptions['readmeinstallchangelog']['desc'] = "Specify custom filenames to parse like README, INSTALL or CHANGELOG files"; + $this->phpDocOptions['readmeinstallchangelog']['type'] = "value"; + + $this->phpDocOptions['general']['message'] ="You can have multiple directories and multiple files, as well as a combination of both options"; + } + + + /** + * create the help message for display on the command-line + * @return string a string containing a help message + */ + function displayHelpMsg() + { + unset($ret); + $ret = "\n"; + foreach($this->phpDocOptions as $data) + { + unset($tag); + $tag = ""; + if (isset($data['tag'])) + { + if (is_array($data['tag'])) { + foreach($data['tag'] as $param) { + $tag .= "$param "; + } + } + $taglen = 34; + $outputwidth = 79; + $tagspace = str_repeat(" ",$taglen); + $tmp = " ".trim($tag).$tagspace; + $tmp = substr($tmp,0,$taglen); + $d = wordwrap(ltrim($data['desc']),($outputwidth-$taglen)); + $dt = explode("\n",$d); + $dt[0] = $tmp .$dt[0]; + for($i=1;$idisplayHelpMsg(); + die(); + } + $setting[$valnext] = $cmd; + foreach( $this->phpDocOptions as $name => $data ) + { + if (!empty($data['tag'])) + { + if (in_array($cmd,$data['tag'])) + { + $valnext = $name; + break; + } + else + { + $valnext = "junk"; + } + } + } + if ($valnext == 'junk' && (strpos(trim($cmd),'-') === 0)) + { + addErrorDie(PDERROR_UNKNOWN_COMMANDLINE,$cmd); + } + } + } else + { + echo "Please use php-cli.exe in windows, or set register_argc_argv On"; + die; + } + /* $setting will always have at least 2 elements + [hidden] => off + [template] => templates/default + */ + if (count($setting) < 3) { + echo $this->displayhelpMsg(); + die(); + } + return $setting; + } + + + /** + * @return array list of files in a directory + * @param string $directory full path to the directory you want the list of + * @param off|on whether to list files that begin with . like .bash_history + */ + function dirList($directory,$hidden = "off") + { + $directory = realpath($directory); + $ret = false; + if (@is_dir($directory)) + { + $ret = array(); + $d = @dir($directory); // thanks to Jason E Sweat (jsweat@users.sourceforge.net) for fix + while($d && ($entry=$d->read()) !== false) { + if (strcmp($entry,".") != 0 && strcmp($entry,"..") != 0) { + if ($hidden == "off") + { + if (substr($entry,0,1) == ".") + { + $getentry = false; + } else { + $getentry = true; + } + + } else { + $getentry = true; + } + + if ($getentry == true) + { + if (is_file($directory . PATH_DELIMITER . $entry)) { + $ret[] = $directory . PATH_DELIMITER . $entry; + } + if (is_dir($directory . PATH_DELIMITER . $entry)) { + $tmp = $this->dirList($directory . PATH_DELIMITER . $entry, $hidden); + if (is_array($tmp)) { + foreach($tmp as $ent) { + $ret[] = $ent; + } + } + } + } + } + } + if ($d) $d->close(); + } else { + die("directory: '$directory' not found\n"); + } + return $ret; + } + + /** + * Retrieve common directory (case-insensitive in windows) + * + * takes the list of files, and returns the subdirectory they share in common, + * so in this list: + * + * + * array( + * "/dir1/dir2/subdir/dir3/filename.ext", + * "/dir1/dir2/subdir/dir4/filename.ext", + * "/dir1/dir2/mydir/dir5/filename.ext"); + * + * + * getBase will return "/dir1/dir2" + * @param array array of strings + */ + function getBase($filelist) + { + $masterPath = false; + foreach($filelist as $path) + { + if (!$masterPath) + { + $masterPath = str_replace('\\','/',dirname($path)); + } else + { + if (dirname($path) != $masterPath) + { + $mp = split(PATH_DELIMITER,$masterPath); + $np = split(PATH_DELIMITER,str_replace('\\','/',dirname($path))); + if (count($np) < count($mp)) + { + $masterPath = join($np, PATH_DELIMITER); + } else + { + $test = false; + $found = false; + for($i=0;$i < count($mp) && $i < count($np);$i++) + { + if (PHPDOCUMENTOR_WINDOWS) + { + if (strtolower($mp[$i]) != strtolower($np[$i])) $found = $i; + } else + { + if ($mp[$i] != $np[$i]) $found = $i; + } + } + if ($found !== false) + { + $mp = array_slice($mp,0,$found); + $masterPath = join($mp,PATH_DELIMITER); + } + } + } + } + } + return $masterPath; + } + + /** + * Retrieve tutorial subdirectories and their contents from the list of + * files to parse + * @param array array of paths (strings) + * @return array array(filelist - tutorials, tutorials) + */ + function getTutorials($filelist) + { + $list = $tutorials = array(); + foreach($filelist as $file) + { + if (strpos($file,'tutorials/') !== false) + { + $tutedir = explode('/',substr($file,strpos($file,'tutorials/'))); + array_shift($tutedir); + if (count($tutedir) <= 3) + { + $res = array(); + // kludge - will need to fix for 2.0 + $res['category'] = $GLOBALS['phpDocumentor_DefaultCategoryName']; + $res['package'] = array_shift($tutedir); + $res['subpackage'] = ''; + if (count($tutedir) > 1) + $res['subpackage'] = array_shift($tutedir); + $f = array_shift($tutedir); + $res['tutename'] = $f; + $f = explode('.',$f); + $res['tutetype'] = array_pop($f); + if ($res['tutetype'] == 'ini') continue; + $res['path'] = $file; + if (@file_exists($file . '.ini')) + { + $res['ini'] = phpDocumentor_parse_ini_file($file . '.ini', true); + } else + { + $res['ini'] = false; + } + $tutorials[] = $res; + } + } else $list[] = $file; + } + return array($list,$tutorials); + } + + /** + * @param string base directory from {@link getBase()} + * @param array file list from {@link dirList()} + * @return array array(filelist - README/INSTALL/CHANGELOG, + * README/INSTALL/CHANGELOG) + */ + function getReadmeInstallChangelog($base,$filelist) + { + $list = $ric = array(); + $names = $GLOBALS['_phpDocumentor_RIC_files']; + foreach($filelist as $file) + { + if ((dirname($file) == $base) && in_array(strtoupper(basename($file)), $names)) + { // be sure to change $this->checkIgnore() if any other files are added here!! + $ric[] = $file; + } else + { + $list[] = $file; + } + } + return array($list,$ric); + } + + function getDirTree($dir, $base_dir, $ignore = array(), $hidden="off") + { + $allfiles = $this->dirList($dir,$hidden); + $struc = array(); + foreach($allfiles as $file) + { + if ($this->checkIgnore(basename($file),dirname($file),$ignore)) continue; + $path = substr(dirname($file),strlen(str_replace('\\','/',realpath($base_dir)))+1); + if (!$path) $path = '/'; + $parts = pathinfo($file); + if (!isset($parts['extension'])) + { + $parts['extension'] = ''; + } + $struc[$path][] = array( + 'file' => $parts['basename'], + 'ext' => $parts['extension'], + 'path' => $file); + } + uksort($struc,'strnatcasecmp'); + foreach($struc as $key => $ind) + { + usort($ind,'Ioinc_sortfiles'); + $struc[$key] = $ind; + $save = $key; + if ($key != '/') + { + $key = explode('/',$key); + while (count($key)) + { + array_pop($key); + if (isset($struc[join('/',$key)])) + { + $struc[join('/',$key)][substr($save,strlen(join('/',$key)) + 1)] = $ind; + unset($struc[$save]); + } + } + } + } + foreach($struc as $key => $ind) + { + if ($key != '/') + { + if (count(explode('/',$key)) == 1) + { + $struc['/'][$key] = $struc[$key]; + unset($struc[$key]); + } + } + } + $tempstruc = $struc; + unset($tempstruc['/']); + $leftover_dirs = array_keys($tempstruc); + $splitdirs = array(); + foreach($leftover_dirs as $dir) + { + $splitdirs[] = explode('/',$dir); + } + $leftover_dirs = array(); + + foreach($splitdirs as $dir) + { + $save = join($dir,'/'); + $struc['/'] = setup_dirs($struc['/'], $dir, $tempstruc[$save]); + unset($struc[$save]); + } + @uksort($struc['/'],'Ioinc_mystrucsort'); + return $struc; + } + + /** + * Reads a file and returns it as a string + * Does basic error checking + * + * file extensions are set in {@link phpdoc.inc} + * + * @global array PHP File extensions, used to validate that $path is a PHP File + * @global array PHP File extensions in a CVS repository, used to validate that $path is a PHP File + * @param string $path + */ + function readPhpFile($path, $quietMode = false) + { + global $_phpDocumentor_cvsphpfile_exts, $_phpDocumentor_phpfile_exts; + // tiberiusblue addition + $cvsExt = $_phpDocumentor_cvsphpfile_exts; + $ext = $_phpDocumentor_phpfile_exts; + if (file_exists($path)) + { + if (is_file($path)) + { + // check extension + $tmp = explode(".",$path); + // tiberiusblue addition + $tmp2 = $tmp; + if (in_array(array_pop($tmp),$ext)) + { + phpDocumentor_out(" -- Parsing file\n"); + flush(); + $fp = fopen($path,"r"); + $ret = fread($fp,filesize($path)); + fclose($fp); + return $ret; + } elseif (in_array(array_pop($tmp2),$cvsExt)) + { + phpDocumentor_out(" CVS file [EXPERIMENTAL]\n"); + flush(); + $fp = fopen($path,"r"); + $ret = fread($fp,filesize($path)); + fclose($fp); + $ret = strstr($ret," + * @param string $file just the file name of the file or directory, + * in the case of directories this is the last dir + * @param string $path the full path + * @param array $ignore + * @return bool true if $path should be ignored, false if it should not + */ + function checkIgnore($file,$path,$ignore,$ignore_no_ext = true) + { + global $_phpDocumentor_RIC_files; + $path = realpath($path); + if (!count($ignore)) return false; + if ($ignore_no_ext && + !in_array(strtoupper($file), $_phpDocumentor_RIC_files)) + { + if (!is_numeric(strpos($file,'.'))) return true; + } + if (!isset($this->ignore) || !$this->ignore) + { + $this->_setupIgnore($ignore); + if (!$this->ignore) + { + return false; + } + } + if (is_array($this->ignore)) + { + foreach($this->ignore as $match) + { + // match is an array if the ignore parameter was a /path/to/pattern + if (is_array($match)) + { + // check to see if the path matches with a path delimiter appended + preg_match('/^' . strtoupper($match[0]).'$/', strtoupper($path) . PATH_DELIMITER,$find); + if (!count($find)) + { + // check to see if it matches without an appended path delimiter + preg_match('/^' . strtoupper($match[0]).'$/', strtoupper($path), $find); + } + if (count($find)) + { + // check to see if the file matches the file portion of the regex string + preg_match('/^' . strtoupper($match[1]).'$/', strtoupper($file), $find); + if (count($find)) + { + return true; + } + } + // check to see if the full path matches the regex + preg_match('/^' . strtoupper($match[0]).'$/', + strtoupper($path . DIRECTORY_SEPARATOR . $file), $find); + if (count($find)) + { + return true; + } + } else + { + // ignore parameter was just a pattern with no path delimiters + // check it against the path + preg_match('/^' . strtoupper($match).'$/', strtoupper($path), $find); + if (count($find)) + { + return true; + } + // check it against the file only + preg_match('/^' . strtoupper($match).'$/', strtoupper($file), $find); + if (count($find)) + { + return true; + } + } + } + } + return false; + } + + /** + * Construct the {@link $ignore} array + * @author Greg Beaver + * @param array strings of files/paths/wildcards to ignore + * @access protected + */ + function _setupIgnore($ignore) + { + $ig = array(); + if (is_array($ignore)) + { + for($i=0; $igetRegExpableSearchString($ignore[$i]); + } else + { + if (basename($ignore[$i]) . PATH_DELIMITER == $ignore[$i]) + $ig[] = $this->getRegExpableSearchString($ignore[$i]); + else + $ig[] = array($this->getRegExpableSearchString($ignore[$i]),$this->getRegExpableSearchString(basename($ignore[$i]))); + } + } + } + if (count($ig)) $this->ignore = $ig; + } else $this->ignore = false; + } + + /** + * Converts $s into a string that can be used with preg_match + * @param string $s string with wildcards ? and * + * @author Greg Beaver + * @return string converts * to .*, ? to ., etc. + */ + function getRegExpableSearchString($s) + { + $y = '\/'; + if (DIRECTORY_SEPARATOR == '\\') + { + $y = '\\\\'; + } + $s = str_replace('/', DIRECTORY_SEPARATOR, $s); + $x = strtr($s, array('?' => '.','*' => '.*','.' => '\\.','\\' => '\\\\','/' => '\\/', + '[' => '\\[',']' => '\\]','-' => '\\-')); + if (strpos($s, DIRECTORY_SEPARATOR) !== false && + strrpos($s, DIRECTORY_SEPARATOR) === strlen($s) - 1) + { + $x = "(?:.*$y$x?.*|$x.*)"; + } + return $x; + } + + /** + * Removes files from the $dir array that do not match the search string in + * $match + * @param array $dir array of filenames (full path) + * @param string $match search string with wildcards + * @author Greg Beaver + * @return string|array listing of every file in a directory that matches + * the search string + */ + function removeNonMatches($dir, $match) + { + $match = $this->getRegExpableSearchString($match); + $nodir = false; + if (!is_array($dir)) + { + $dir = array($dir); + $nodir = true; + } + foreach($dir as $i => $file) + { + preg_match('/^'.$match.'$/',basename($file),$find); + if (!count($find)) unset($dir[$i]); + } + if ($nodir) return $dir[0]; + return $dir; + } + + /** + * Take a filename with wildcards and return all files that match the + * wildcards + * @param string $file a full path from the -f command-line parameter, with + * potential * and ? wildcards. + * @return mixed if $file contains wildcards, returns an array of matching + * files, otherwise returns false + * @author Greg Beaver + */ + function getAllFiles($file) + { + $path = realpath(dirname($file)); + $file = basename($file); + // any wildcards? + if (is_numeric(strpos($file,'?')) || is_numeric(strpos($file,'*'))) + { + $files = $this->dirList($path); + $a = $this->removeNonMatches($files,$file); + return $a; + } + return false; + } +} + +/**#@+ + * Sorting functions for the file list + * @param string + * @param string + */ +function Ioinc_sortfiles($a, $b) +{ + return strnatcasecmp($a['file'],$b['file']); +} + +function Ioinc_mystrucsort($a, $b) +{ + if (is_numeric($a) && is_string($b)) return 1; + if (is_numeric($b) && is_string($a)) return -1; + if (is_numeric($a) && is_numeric($b)) + { + if ($a > $b) return 1; + if ($a < $b) return -1; + if ($a == $b) return 0; + } + return strnatcasecmp($a,$b); +} +/**#@-*/ + +/** + * Recursively add all the subdirectories of $contents to $dir without erasing anything in + * $dir + * @param array + * @param array + * @return array processed $dir + */ +function set_dir($dir,$contents) +{ + while(list($one,$two) = each($contents)) + { + if (isset($dir[$one])) + { + $dir[$one] = set_dir($dir[$one],$contents[$one]); + } else $dir[$one] = $two; + } + return $dir; +} + +/** + * Recursively move contents of $struc into associative array + * + * The contents of $struc have many indexes like 'dir/subdir/subdir2'. + * This function converts them to + * array('dir' => array('subdir' => array('subdir2'))) + * @param array struc is array('dir' => array of files in dir,'dir/subdir' => array of files in dir/subdir,...) + * @param array array form of 'dir/subdir/subdir2' array('dir','subdir','subdir2') + * @return array same as struc but with array('dir' => array(file1,file2,'subdir' => array(file1,...))) + */ +function setup_dirs($struc,$dir,$contents) +{ + if (!count($dir)) + { + foreach($contents as $dir => $files) + { + if (is_string($dir)) + { + if (strpos($dir,'/')) + { + $test = true; + $a = $contents[$dir]; + unset($contents[$dir]); + $b = explode('/',$dir); + $c = array_shift($b); + if (isset($contents[$c])) + { + $contents[$c] = set_dir($contents[$c],setup_dirs(array(),$b,$a)); + } else $contents[$c] = setup_dirs(array(),$b,$a); + } + } + } + return $contents; + } + $me = array_shift($dir); + if (!isset($struc[$me])) $struc[$me] = array(); + $struc[$me] = setup_dirs($struc[$me],$dir,$contents); + return $struc; +} + +if (!function_exists('get_include_path')) { +function get_include_path() +{ + return ini_get('include_path'); +} +} +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/LinkClasses.inc b/buildscripts/PhpDocumentor/phpDocumentor/LinkClasses.inc new file mode 100644 index 00000000..d122f0d4 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/LinkClasses.inc @@ -0,0 +1,206 @@ +path = $path; + $this->fileAlias = $fileAlias; + $this->name = $name; + $this->category = $category; + $this->package = $package; + $this->subpackage = $subpackage; + } +} + +/** + * procedural page link + * @package phpDocumentor + * @subpackage Links + */ +class pageLink extends abstractLink +{ + /** @var string */ + var $type = 'page'; +} + +/** + * function link + * @package phpDocumentor + * @subpackage Links + */ +class functionLink extends abstractLink +{ + /** @var string */ + var $type = 'function'; +} + +/** + * define link + * @package phpDocumentor + * @subpackage Links + */ +class defineLink extends abstractLink +{ + /** @var string */ + var $type = 'define'; +} + +/** + * global variable link + * @package phpDocumentor + * @subpackage Links + */ +class globalLink extends abstractLink +{ + /** @var string */ + var $type = 'global'; +} + +/** + * class link + * @package phpDocumentor + * @subpackage Links + */ +class classLink extends abstractLink +{ + /** @var string */ + var $type = 'class'; +} + +/** + * method link + * @package phpDocumentor + * @subpackage Links + */ +class methodLink extends abstractLink +{ + /** @var string */ + var $type = 'method'; + /** @var string */ + var $class = ''; + + /** + * @param string class name + * @param string full path to file containing element + * @param string page name, as configured by {@link Parser::parse} + * @param string element name + * @param string package element is in + * @param string subpackage element is in + */ + function addLink($class, $path ,$fileAlias,$name,$package,$subpackage, $category = false) + { + $this->class = $class; + abstractLink::addLink($path, $fileAlias,$name,$package,$subpackage, $category); + } +} + +/** + * class variable link + * @package phpDocumentor + * @subpackage Links + */ +class varLink extends methodLink +{ + /** @var string */ + var $type = 'var'; +} + +/** + * class constant link + * @package phpDocumentor + * @subpackage Links + */ +class constLink extends methodLink +{ + /** @var string */ + var $type = 'const'; +} + +/** + * tutorial link + * @package phpDocumentor + * @subpackage Links + */ +class tutorialLink extends abstractLink +{ + /**#@+ @var string */ + var $type = 'tutorial'; + var $section = ''; + var $title = false; + /**#@-*/ + + /** + * @param string section/subsection name + * @param string full path to file containing element + * @param string page name, as configured by {@link Parser::parse} + * @param string element name + * @param string package element is in + * @param string subpackage element is in + * @param string title of tutorial + */ + function addLink($section,$path,$name,$package,$subpackage,$title = false, $category = false) + { + $this->section = $section; + $this->title = $title; + parent::addLink($path,'',$name,$package,$subpackage, $category); + } +} +?> \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/PackagePageElements.inc b/buildscripts/PhpDocumentor/phpDocumentor/PackagePageElements.inc new file mode 100644 index 00000000..1b71b6b7 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/PackagePageElements.inc @@ -0,0 +1,387 @@ +, + * contains every other tag and all text. + * @tutorial tutorials.pkg + * @package phpDocumentor + * @subpackage Tutorial + */ +/** + * Represents sections. + * + * These sections are interpreted as plain text + * @package phpDocumentor + * @subpackage Tutorial + */ +class parserCData extends parserStringWithInlineTags +{ + /** + * @uses Converter::getCData() convert contents to text + * @param Converter + */ + function Convert(&$c, $postprocess = true) + { + $val = $this->value; + if ($postprocess) + foreach($this->value as $key => $value) + { + if (is_string($value)) $this->value[$key] = $c->getCData($value); + } + $this->cache = false; + $x = parent::Convert($c, false); + $this->value = $val; + return $x; + } +} +/** + * a standard XML DocBook Tag + * + * This class is designed to represent all DocBook tags. It is intelligent + * enough to understand the tag, and also the <refname> tag for + * as title for <refentry> + * @since 1.2 + * @package phpDocumentor + * @subpackage Tutorial + */ +class parserXMLDocBookTag extends parserStringWithInlineTags +{ + /** + * Attributes from the XML tag + * + * Format: array(attrname => attrvalue, attrname => attrvalue,...) + * @var array + */ + var $attributes = array(); + /** + * Name of the tag + * @var string + */ + var $name; + /**#@+ @access private */ + /** @var parserCData */ + var $_cdata; + /** @var parserTag */ + var $_title; + /** @var parserIdLineTag */ + var $_id; + /** + * Set to <refpurpose> in <refsynopsisdiv> + * @var parserTag + */ + var $_description; + /**#@-*/ + /** + * @param string tag name + */ + function parserXMLDocBookTag($name) + { + $this->name = $name; + } + + /** + * @param Converter + * @param boolean + * @uses Converter::TranslateTag() Calls this to enclose the contents of the + * DocBook tag based on the values in template options.ini file + */ + function Convert(&$c, $postprocess = true) + { + $value = parent::Convert($c, $postprocess); + $simvalue = parent::Convert($c, false); + foreach($this->attributes as $a => $v) + { + $this->attributes[$a] = (is_string($v) ? $v : $v->Convert($c, $postprocess)); + } + if (isset($this->_title)) + { + list($this->attributes,$value) = $c->ConvertTitle($this->name, $this->attributes, $this->_title->Convert($c, $postprocess), $value); + } + return $c->TranslateTag($this->name,$this->attributes,$value,$simvalue); + } + + /** + * Begin a new CData section + * @see addCData() + */ + function startCData() + { + $this->_cdata = new parserCData; + } + + /** + * Adds {@link $_cdata} to {@link $value} + */ + function endCData() + { + $this->value[] = $this->_cdata; + unset($this->_cdata); + } + + /** + * Retrieve either the table of contents index, or the location that + * the TOC will go + * @see setTOC() + * @param false|integer either an index of the {@}toc} tag in $this->value + * or false, if the next index value of $this->value + * is needed + */ + function getTOC($state = false) + { + if ($state !== false) return $this->value[$state]; + return count($this->value); + } + + /** + * @param integer index of the TOC in $this->value + * @param parserTocInlineTag + */ + function setTOC($state, $val) + { + $this->value[$state] = $val; + } + + /** + * add a word to CData + * @param string + */ + function addCData($word) + { + $this->_cdata->add($word); + } + + /** + * Add an xml tag attribute name="value" pair + * + * if the attribute is id, value must be a {@link parserIdInlineTag} + * @param string attribute name + * @param string|parserIdInlineTag value of attribute + */ + function addAttribute($name,$value) + { + $this->attributes[$name] = $value; + if ($name == 'id') + { + // fix 1153593 + if (is_string($value)) + { + addWarning(PDERROR_ID_MUST_BE_INLINE,$this->name,$value,$this->name,$value); + } else { + $this->setId($value); + } + } + } + + /** + * Set the title of a DocBook tag section. + * + * For most DocBook tags, the title is represented with a <title> + * tag pair. The top-level tag is a little different. Instead + * of using , phpDocumentor uses the contents of the + * tag in the tag + * @param parserXMLDocBookTag the title element + */ + function setTitle($title) + { + $this->_title = $title; + } + + /** + * If the id attribute is present, this method will set its id + * @param parserIdInlineTag + */ + function setId($id) + { + $this->_id = $id; + } + + /** + * Return converter-specific formatting of ID. + * + * Passes $c to {@link parserIdInlineTag::Convert()} + * @param Converter + * @return string + */ + function getId(&$c) + { + if ($this->_id) return trim($this->_id->Convert($c)); + } + + /** + * Determine whether the docbook element has a title + * @return boolean + */ + function hasTitle() + { + return isset($this->_title); + } + + /** + * Retrieve Converter-specific formatting of the title of this element + * @return string + * @param Converter + */ + function getTitle(&$c) + { + if ($this->name == 'refentry') + { + foreach($this->value as $tag) + { + if (is_object($tag) && $tag->name == 'refnamediv') + { + return $tag->getTitle($c); + } + } + } + if ($this->name == 'refnamediv') + { + foreach($this->value as $tag) + { + if (is_object($tag) && $tag->name == 'refname') + { + $t = new parserStringWithInlineTags; + foreach($tag->value as $val) $t->add($val); + $this->_title = $t; + } + if (is_object($tag) && $tag->name == 'refpurpose') + { + $t = new parserStringWithInlineTags; + foreach($tag->value as $val) $t->add($val); + $this->_description = $t; + } + } + } + if (isset($this->_title)) + return $this->_title->Convert($c); + if (is_object($this->value[0])) return $this->value[0]->getTitle($c); + if (isset($this->value[1])) + if (is_object($this->value[1])) return $this->value[1]->getTitle($c); + return ''; + } + + /** + * Retrieve the contents of a subsection + * + * This method uses the $_id members of nested docbook tags to retrieve + * the section defined by $subsection + * @param Converter + * @param string converter-specific subsection + */ + function getSubsection(&$c,$subsection) + { + if (!is_object($this->_id)) { + return false; + } + $search = phpDocumentor_clone($this->_id); + if (is_string($this->_id)) return false; + if (phpDocumentor_get_class($search) != 'parseridinlinetag') return false; + $search->id = $subsection; + foreach($this->value as $el) + { + if (phpDocumentor_get_class($el) == 'parserxmldocbooktag') + { + if ($el->getId($c) == $search->Convert($c)) + { + return $el; + } elseif ($a = $el->getSubsection($c,$subsection)) + { + return $a; + } + } + } + return false; + } + + /** + * Add contents to this tag. + * + * There are four kinds of data in a DocBook tutorial: + * 1. tags - normal tags like + * 2. entities - normal entities like ” + * 3. - character data that should not be interpreted, + * like contents + * 4. text - normal non-markup text + * + * All four kinds of data are added here + * @param parserEntity|parserCData|parserXMLDocBookTag|string nested tag, + * entity, or text + */ + function add($el) + { + if (is_string($el)) return parent::add($el); + if (phpDocumentor_get_class($el) == 'parserxmldocbooktag') + { + if ($el->name == 'title') + { + $this->setTitle($el); + } else return parent::add($el); + } else return parent::add($el); + } +} + +/** + * a standard entity like ” + * + * This class is designed to represent all DocBook entities. + * @since 1.2 + * @package phpDocumentor + * @subpackage Tutorial + */ +class parserEntity +{ + /** + * @param string entity name + */ + function parserEntity($name) + { + $this->value = $name; + } + + /** + * @uses Converter::TranslateEntity() convert contents to text + * @param Converter + * @return string + */ + function Convert(&$c, $postprocess = true) + { + if ($postprocess) + return $c->TranslateEntity($this->value); + else + { + $trans_tbl = get_html_translation_table (HTML_ENTITIES); + $trans_tbl = array_flip ($trans_tbl); + $ret = strtr ('&'.$this->value.';', $trans_tbl); + return $ret; + } + } +} +?> \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Parser.inc b/buildscripts/PhpDocumentor/phpDocumentor/Parser.inc new file mode 100644 index 00000000..55e67685 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Parser.inc @@ -0,0 +1,3185 @@ + is encountered in parsing an @author tag*/ +define("PARSER_EVENT_DOCKEYWORD_EMAIL" , 114); +/** currently parsing an email in brackets in an @author tag of a DocBlock */ +define("STATE_DOCKEYWORD_EMAIL" , 214); + +/** used when an array definition is encountered in parsing */ +define("PARSER_EVENT_ARRAY" , 115); +/** currently parsing an array */ +define("STATE_ARRAY" , 215); + +/** used when a var statement is encountered in parsing a class definition */ +define("PARSER_EVENT_VAR" , 116); +/** currently parsing a Class variable */ +define("STATE_VAR" , 216); + +/** used when a function definition is encountered in parsing */ +define("PARSER_EVENT_FUNCTION" , 117); +/** currently parsing a Function or Method */ +define("STATE_FUNCTION" , 217); + +/** used when a ? > (with no space) is encountered in parsing */ +define("PARSER_EVENT_OUTPHP" , 118); +/** currently out of php code */ +define("STATE_OUTPHP" , 218); + +/** used when an inline {@tag} is encountered in parsing a DocBlock */ +define("PARSER_EVENT_INLINE_DOCKEYWORD" , 119); +/** currently parsing an inline tag like { @link} in a DocBlock */ +define("STATE_INLINE_DOCKEYWORD" , 219); + +/** used when a define statement's opening parenthesis is encountered in parsing */ +define("PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS" , 120); +/** currently parsing an inner parenthetical statement of a define( ) */ +define("STATE_DEFINE_PARAMS_PARENTHESIS" , 220); + +define("PARSER_EVENT_END_STATEMENT", 121); + +/** used when a <<< is encountered in parsing */ +define("PARSER_EVENT_EOFQUOTE" , 122); +/** currently parsing a string defined using Perl <<< */ +define("STATE_EOFQUOTE" , 222); + +/** used when an include/require/include_once/include_once statement is encountered in parsing */ +define("PARSER_EVENT_INCLUDE" , 123); +/** currently parsing an include/require/include_once/include_once */ +define("STATE_INCLUDE" , 223); + +/** used when an opening parenthesis of an include/require/include_once/include_once statement is encountered in parsing */ +define("PARSER_EVENT_INCLUDE_PARAMS" , 124); +/** currently parsing the stuff in ( ) of a define statement */ +define("STATE_INCLUDE_PARAMS" , 224); + +/** used when an inner ( ) is encountered while parsing an include/require/include_once/include_once statement */ +define("PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS" , 125); +/** currently parsing an inner parenthetical statement of an include/includeonce/require/requireonce( ) */ +define("STATE_INCLUDE_PARAMS_PARENTHESIS" , 225); + +/** used when parsing the desc part of a docblock */ +define("PARSER_EVENT_DESC" , 126); +/** currently parsing the desc part of a docblock */ +define("STATE_DESC" , 226); + +/** used when parsing the @tag block of a docblock */ +define("PARSER_EVENT_TAGS" , 127); +/** currently parsing the @tag block of a docblock */ +define("STATE_TAGS" , 227); + +/** used when parsing a global variable declaration */ +define("PARSER_EVENT_DEFINE_GLOBAL" , 128); +/** currently parsing a global variable declaration */ +define("STATE_GLOBAL" , 228); + +/** used when parsing the default value in a global variable declaration */ +define("PARSER_EVENT_GLOBAL_VALUE" , 129); +/** currently parsing the default value in a global variable declaration */ +define("STATE_GLOBAL_VALUE" , 229); + +/** used when parsing a "global $var1, $var2;" declaration in a function */ +define("PARSER_EVENT_FUNC_GLOBAL" , 130); +/** currently parsing a "global $var1, $var2;" declaration in a function */ +define("STATE_FUNC_GLOBAL" , 230); + +/** used when parsing a "static $var1, $var2;" declaration in a function */ +define("PARSER_EVENT_STATIC_VAR" , 131); +/** currently parsing a "static $var1, $var2;" declaration in a function */ +define("STATE_STATIC_VAR" , 231); + +/** used when parsing the value in a "static $var1 = x" declaration in a function */ +define("PARSER_EVENT_STATIC_VAR_VALUE" , 132); +/** currently parsing the value in a "static $var1 = x" declaration in a function */ +define("STATE_STATIC_VAR_VALUE" , 232); + +/** used when encountering a /**#@+ comment marking a new docblock template */ +define("PARSER_EVENT_DOCBLOCK_TEMPLATE" , 133); +/** currently parsing the value in a "static $var1 = x" declaration in a function */ +define("STATE_DOCBLOCK_TEMPLATE" , 233); + +/** used when encountering a /**#@-* / comment (no space) marking the end of using a docblock template */ +define("PARSER_EVENT_END_DOCBLOCK_TEMPLATE" , 134); +/** currently parsing the value in a "static $var1 = x" declaration in a function */ +define("STATE_END_DOCBLOCK_TEMPLATE" , 234); + +/** used by the {@link HighlightParser} only, when a method starts */ +define("PARSER_EVENT_METHOD" , 135); +/** currently parsing a method using the {@link HighlightParser} */ +define("STATE_METHOD" , 235); + +/** used by the {@link HighlightParser} only, when a method body is parsed */ +define("PARSER_EVENT_METHOD_LOGICBLOCK" , 136); +/** currently parsing the method body using the {@link HighlightParser} */ +define("STATE_METHOD_LOGICBLOCK" , 236); + +/** used by the {@link HighlightParser} only, when ->var or ->function() is encountered in a method */ +define("PARSER_EVENT_CLASS_MEMBER" , 137); +/** currently parsing a class member using the {@link HighlightParser} */ +define("STATE_CLASS_MEMBER" , 237); + +/** used by the {@link HighlightParser} only, when {$var} is encountered in a string */ +define("PARSER_EVENT_QUOTE_VAR" , 138); +/** currently parsing a {$encapsed_var} using the {@link HighlightParser} */ +define("STATE_QUOTE_VAR" , 238); + +/** used when parsing an access modifier */ +define("PARSER_EVENT_ACCESS_MODIFIER" , 139); +/** currently parsing an access modifier */ +define("STATE_ACCESS_MODIFIER" , 239); + +/** used when a class implements interfaces */ +define("PARSER_EVENT_IMPLEMENTS" , 140); +/** currently parsing an implements clause */ +define("STATE_IMPLEMENTS" , 240); + +/** used when a class implements interfaces */ +define("PARSER_EVENT_CLASS_CONSTANT" , 141); +/** currently parsing a class constant */ +define("STATE_CLASS_CONSTANT" , 241); + +/** used when a variable value is an array */ +define("PARSER_EVENT_VAR_ARRAY" , 142); +/** currently parsing a variable value is an array */ +define("STATE_VAR_ARRAY" , 242); + +/** used when a comment is found in a variable array value */ +define("PARSER_EVENT_VAR_ARRAY_COMMENT" , 143); +/** currently parsing a comment in a variable array value */ +define("STATE_VAR_ARRAY_COMMENT" , 243); + +if (!defined('T_INTERFACE')) +{ + define('T_INTERFACE', 'foo'); + if (!defined('T_CONST')) { + define('T_CONST', 'foo'); + } + define('T_ABSTRACT', 'foo'); + define('T_PRIVATE', 'foo'); + define('T_PUBLIC', 'foo'); + define('T_PROTECTED', 'foo'); + define('T_FINAL', 'foo'); + define('T_IMPLEMENTS', 'foo'); +} +if (!defined('T_DOC_COMMENT')) +{ + define('T_DOC_COMMENT', T_ML_COMMENT); +} +/** + * PHP Parser for PHP 4.2.3- + * + * This parser is slower than the tokenizer-based parser, and is deprecated. + * @author Joshua Eichorn + * @author Gregory Beaver + * @version $Id: Parser.inc,v 1.1 2005/10/17 18:36:56 jeichorn Exp $ + * @package phpDocumentor + * @subpackage Parsers + * @deprecated in favor of {@link phpDocumentorTParser} + */ +class Parser extends Publisher +{ + /**#@+ + * @access private + */ + /** + * Word parser + * @see WordParser + */ + var $wp; + + /** + * temporary parser variables + */ + var $p_vars = array('func' => false, 'function_data' => '', 'quote_data' => '', 'event_stack' => false, 'last_pevent' => 0, + 'two_words_ago' => '', 'temp_word' => '', 'docblock' => false, 'line' => array(), 'linecount' => 0, 'startword' => '', + 'periodline' => 0, 'shortdesc' => '', 'docblock_desc' => '', 'class' => false, 'source_location' => '', + 'define_params_data' => '', 'define' => false, 'define_name' => '', 'define_value' => '', 'var' => false, + 'oldtoken' => false, 'comment_data' => '', 'function_param' => NULL, 'inline_dockeyword_type' => false, + 'inline_dockeyword_data' => false, 'dockeyword_type' => false, 'dockeyword_data' =>false, 'param_var' => false, + 'include_name' => '', 'include_value' => '','include' => false, 'return_type' => '', 'cur_class' => '', + 'function_data' => false, 'varname' => '', 'returntype' => false, 'vartype' => false, 'paramtype' => false, + 'tagname' => '', 'find_global' => '', 'global_type' => '', 'paramname' => false, 'statics' => array(), + 'static_count' => 0, 'static_val' => array(), 'docblock_type' => 'docblock', 'seelement' => false); + + /** + * parser flags, for states that don't warrant a new event (like new line in a docblock) + */ + var $p_flags = array('docblocknewline' => false, 'docblockintags' => false, 'useperiod' => false, + 'definename_isset' => false, 'define_parens' => false, 'reset_quote_data' => false, + 'in_desc' => true, 'in_tag' => false, 'newline' => true, 'tempnewline' => false, + 'start_docblock' => false, 'includename_isset' => false, 'return_isset' => false, + 'is_return' => false, 'in_class' => false, 'asterisk' => false, 'var_equals' => false, + 'arrayinvarname' => false, 'valid_newline' => true, 'startline' => false, + 'function_global' => false, 'define_global' => false, 'static_value' => false,'funcparam_val' => false, + 'get_source' => false, 'getting_source' => false); + + /** + * lookup table for event handler methods + * @see Parser::parse() + */ + var $eventHandlers = array( + 'handleArray' => PARSER_EVENT_ARRAY, + 'handleClass' => PARSER_EVENT_CLASS, + 'handleComment' => PARSER_EVENT_COMMENT, + 'handleDocBlockTemplate' => PARSER_EVENT_DOCBLOCK_TEMPLATE, + 'handleEndDocBlockTemplate' => PARSER_EVENT_END_DOCBLOCK_TEMPLATE, + 'handleEscape' => PARSER_EVENT_ESCAPE, + 'handleLogicBlock' => PARSER_EVENT_LOGICBLOCK, + 'defaultHandler' => PARSER_EVENT_NOEVENTS, +// 'defaultHandler' => PARSER_EVENT_COMMENTBLOCK, (set in constructor below) +// 'defaultHandler' => PARSER_EVENT_OUTPHP, + 'handleDefine' => PARSER_EVENT_DEFINE, + 'handleDefineParams' => PARSER_EVENT_DEFINE_PARAMS, + 'handleDefineParamsParenthesis' => PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS, + 'handleIncludeParamsParenthesis' => PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS, +// 'handleDocBlock' => PARSER_EVENT_DOCBLOCK, + 'BetterhandleDocBlock' => PARSER_EVENT_DOCBLOCK, + 'handleTags' => PARSER_EVENT_TAGS, + 'handleDesc' => PARSER_EVENT_DESC, +// 'handleDockeyword' => PARSER_EVENT_DOCKEYWORD, + 'handleTag' => PARSER_EVENT_DOCKEYWORD, + 'handleDockeywordEmail' => PARSER_EVENT_DOCKEYWORD_EMAIL, + 'handleEOFQuote' => PARSER_EVENT_EOFQUOTE, + 'handleFunction' => PARSER_EVENT_FUNCTION, + 'handleFunctionParams' => PARSER_EVENT_FUNCTION_PARAMS, + 'handleFuncGlobal' => PARSER_EVENT_FUNC_GLOBAL, + 'handleGlobal' => PARSER_EVENT_DEFINE_GLOBAL, + 'handleGlobalValue' => PARSER_EVENT_GLOBAL_VALUE, + 'handleInlineDockeyword' => PARSER_EVENT_INLINE_DOCKEYWORD, + 'handleInclude' => PARSER_EVENT_INCLUDE, + 'handleIncludeParams' => PARSER_EVENT_INCLUDE_PARAMS, + 'handleQuote' => PARSER_EVENT_QUOTE, + 'handlePhpCode' => PARSER_EVENT_PHPCODE, + 'handleSingleQuote' => PARSER_EVENT_SINGLEQUOTE, + 'handleStaticVar' => PARSER_EVENT_STATIC_VAR, + 'handleStaticValue' => PARSER_EVENT_STATIC_VAR_VALUE, + 'handleVar' => PARSER_EVENT_VAR, + ); + + /** + * event handlers for @tags + * @tutorial tags.pkg + */ + var $tagHandlers = array( + '*' => 'defaultTagHandler', + 'category' => 'categoryTagHandler', + 'example' => 'exampleTagHandler', + 'filesource' => 'invalidTagHandler', + 'return' => 'returnTagHandler', + 'returns' => 'returnTagHandler', + 'var' => 'varTagHandler', + 'package' => 'packageTagHandler', + 'param' => 'paramTagHandler', + 'parameter' => 'paramTagHandler', + 'global' => 'globalTagHandler', + 'staticvar' => 'staticvarTagHandler', + 'uses' => 'usesTagHandler' + ); + + var $laststart = false; + + /** + * An array of allowable @tags + */ + var $allowableTags; + + + /** + * An array of allowed inline @tags + */ + var $allowableInlineTags; + + /** + * Sets the states up, and creates a new WordParser + */ + + /** + * an array of parsing tokens organized by event number. + * A token is defined as the smallest group of characters that separates or + * defines a new parser element. In English, a space or punctuation are + * tokens that separate words. in PHP, tokens may be //, or even " + * Format: array(eventnum =>array(token1, token2, token3, ...),...) + * @var array + */ + var $tokens; + + /** + * array of events that are raised, organized by the tokens that raise them. + * Format: array(eventnum => array(token => neweventnum, token2 => neweventnum2,...),...) + * @var array + */ + var $pushEvent; + + /** + * array of tokens that end an event, organized by event + * Format: array(eventnum => array(token => neweventnum, token2 => neweventnum2,...),...) + * @var array + */ + var $popEvent; + /**#@-*/ + + /** + * Set up invariant parsing variables + */ + function Parser() + { + $this->allowableTags = $GLOBALS['_phpDocumentor_tags_allowed']; + $this->allowableInlineTags = $GLOBALS['_phpDocumentor_inline_doc_tags_allowed']; + $this->wp = new WordParser; + // strange PHP 4.0.6 behavior: it converts constants to strings without warning if it's an array index + $this->eventHandlers = array_flip($this->eventHandlers); + $this->eventHandlers[PARSER_EVENT_COMMENTBLOCK] = 'defaultHandler'; + $this->eventHandlers[PARSER_EVENT_OUTPHP] = 'defaultHandler'; + $this->subscribe(PHPDOCUMENTOR_EVENT_NEWLINENUM,$GLOBALS['phpDocumentor_errors']); + $this->subscribe(PHPDOCUMENTOR_EVENT_NEWFILE,$GLOBALS['phpDocumentor_errors']); + } + + /** + * Parse a new file + * + * @param string $parse_data + * @param string $path + * @param int $base number of directories to drop off the bottom when creating names using path + * @staticvar integer used for recursion limiting if a handler for an event is not found + * @return bool + */ + function parse (&$parse_data, $path, $base = 0, $packages = false) + { + global $_phpDocumentor_options; + static $endrecur = 0; + $this->p_vars = array('func' => false, 'function_data' => '', 'quote_data' => '', 'event_stack' => false, 'last_pevent' => 0, + 'two_words_ago' => '', 'temp_word' => '', 'docblock' => false, 'line' => array(), 'linecount' => 0, 'startword' => '', + 'periodline' => 0, 'shortdesc' => '', 'docblock_desc' => '', 'class' => false, 'source_location' => '', + 'define_params_data' => '', 'define' => false, 'define_name' => '', 'define_value' => '', 'var' => false, + 'oldtoken' => false, 'comment_data' => '', 'function_param' => NULL, 'inline_dockeyword_type' => false, + 'inline_dockeyword_data' => false, 'dockeyword_type' => false, 'dockeyword_data' =>false, 'param_var' => false, + 'include_name' => '', 'include_value' => '','include' => false, 'return_type' => '', 'cur_class' => '', + 'function_data' => false, 'varname' => '', 'returntype' => false, 'vartype' => false, 'paramtype' => false, + 'tagname' => '', 'find_global' => '', 'global_type' => '', 'paramname' => false, 'statics' => array(), + 'static_count' => 0, 'static_val' => array(), 'docblock_type' => 'docblock', 'linenum' => false, + 'seelement' => false); + + $this->p_flags = array('docblocknewline' => false, 'docblockintags' => false, 'useperiod' => false, + 'definename_isset' => false, 'define_parens' => false, 'reset_quote_data' => false, + 'in_desc' => true, 'in_tag' => false, 'newline' => true, 'tempnewline' => false, + 'start_docblock' => false, 'includename_isset' => false, 'return_isset' => false, + 'is_return' => false, 'in_class' => false, 'asterisk' => false, 'var_equals' => false, + 'arrayinvarname' => false, 'valid_newline' => true, 'startline' => false, + 'function_global' => false, 'define_global' => false, 'static_value' => false,'funcparam_val' => false, + 'get_source' => false, 'getting_source' => false, 'in_define' => false, 'in_include' => false, + 'in_var' => false, 'in_global' => false); + $this->p_vars['parsepath'] = $path; + $this->setupStates(); + if (strlen($parse_data) == 0) + { + return false; + } + + // initialize variables so E_ALL error_reporting doesn't complain + $pevent = 0; + $word = 0; + $this->p_vars['event_stack'] = new EventStack; + + $this->wp->setup($parse_data); + + + $page = new ParserPage; + $page->setPath($path); + $page->setPackageOutput($packages); + $page->setFile(basename($path)); + $this->publishEvent(PHPDOCUMENTOR_EVENT_NEWFILE,basename($path)); + //$name = str_replace("/","_",dirname($path)) . "_" . array_shift(explode(".",$page->getFile())); + // fc@fc.clever-soft.com 11/29/2001 + $name = str_replace(PATH_DELIMITER,"_",dirname($path)) . "_" . str_replace(".","_",$page->getFile()); + $tmp = explode("_",$name); + $name = str_replace(':','_',implode("_",array_slice($tmp,$base))); + // if base is '', drive letter is present in windows + + $page->setName($name); + $temploc = $_phpDocumentor_options['Program_Root'] . PATH_DELIMITER. implode(PATH_DELIMITER, + array_slice(explode(PATH_DELIMITER,$path),$base)); + + if ($temploc == $_phpDocumentor_options['Program_Root'] . PATH_DELIMITER) $temploc .= $path; + + $this->p_vars['source_location'] = $source_location = $temploc; + $page->setSourceLocation($source_location); + + $this->publishEvent(PHPDOCUMENTOR_EVENT_PAGE,$page); + unset($page); + $this->p_flags['reset_quote_data'] = true; + + do + { + $lpevent = $pevent; + $pevent = $this->p_vars['event_stack']->getEvent(); + if ($lpevent != $pevent) + { + $this->p_vars['last_pevent'] = $lpevent; + } + + if ($this->p_vars['last_pevent'] != $pevent) + { + // its a new event so the word parser needs to be reconfigured + $this->configWordParser($pevent); + } + + $this->publishEvent(PHPDOCUMENTOR_EVENT_NEWSTATE,($pevent + 100)); + + if ($pevent == PARSER_EVENT_GLOBAL_VALUE || $pevent == PARSER_EVENT_DOCBLOCK || $pevent == PARSER_EVENT_DOCBLOCK_TEMPLATE) + { + $this->wp->setWhitespace(true); + } + + $this->p_vars['last_word'] = $word; + $word = $this->wp->getWord(); + // in wordparser, have to keep track of lines + $this->publishEvent(PHPDOCUMENTOR_EVENT_NEWLINENUM, $this->wp->linenum); + + if (0)//PHPDOCUMENTOR_DEBUG == true) + { + echo "\nLAST: |" . $this->p_vars['last_word'] . "|\n"; + echo "PEVENT: " . $this->getParserEventName($pevent) . "\n"; + echo "LASTPEVENT: " . $this->getParserEventName($this->p_vars['last_pevent']) . "\n"; + echo $this->wp->getPos() . ": |$word|\n--------------------------\n\n"; + } + if ($this->p_flags['get_source']) + { + if ($pevent == PARSER_EVENT_FUNCTION) + { + $this->wp->retrievesource("function $word"); + $this->p_flags['get_source'] = false; + $this->p_flags['getting_source'] = true; + } + } + if (false)//$this->p_flags['getting_source'] && ($pevent == PARSER_EVENT_DOCBLOCK) || ($pevent == PARSER_EVENT_NOEVENTS)) + { + addError(PDERROR_SOURCE_TAG_FUNCTION_NOT_FOUND); + // throw away source + $this->wp->getSource(); + } + if (isset($this->eventHandlers[$pevent])) + { + $handle = $this->eventHandlers[$pevent]; + $this->$handle($word, $pevent); + } else + { + debug('WARNING: possible error, no handler for event number '.$pevent); + if ($endrecur++ == 25) + { + die("FATAL ERROR, recursion limit reached"); + } + } + } while (!($word === false)); + $this->publishEvent(PHPDOCUMENTOR_EVENT_NEWSTATE,PHPDOCUMENTOR_EVENT_END_PAGE); + } + + /**#@+ + * @access private + * @param string token parsed from source + * @param integer parser constant from {@link Parser.inc} + */ + /** + * handler for NOEVENTS, OUTPHP, COMMENTBLOCK + */ + + function defaultHandler($word, $pevent) + { + $this->checkEventPush( $word, $pevent); + $this->checkEventPop($word,$pevent); + } + + /** + * handler for LOGICBLOCK + * + * Logic Blocks are the stuff between { and } in a function/method. A + * logic block can clearly contain other logic blocks, as in: + * + * + * function test($a) + * { + * if (testcondition) + * { // nested logic block + * } + * } + * + * + * So, the exit portion of the logic block handler must check to see if the + * logic block being exited is the top-level, and it does this by retrieving + * the last event from the stack. If it is a function (and not a logic block) + * then it backs up the word parser so that the function will exit properly. + * + * {@source 11} + */ + + function handleLogicBlock($word, $pevent) + { + $a = $this->checkEventPush( $word, $pevent); + if ($a == PARSER_EVENT_FUNC_GLOBAL || $a == PARSER_EVENT_STATIC_VAR) + { + if (substr($this->p_vars['last_word'],strlen($this->p_vars['last_word']) - 1,1) != ' ' && substr($this->p_vars['last_word'],strlen($this->p_vars['last_word']) - 1,1) != "\t" && substr($this->p_vars['last_word'],strlen($this->p_vars['last_word']) - 1,1) != "\n" && substr($this->p_vars['last_word'],strlen($this->p_vars['last_word']) - 1,1) != ";" && substr($this->p_vars['last_word'],strlen($this->p_vars['last_word']) - 1,1) != "}" && substr($this->p_vars['last_word'],strlen($this->p_vars['last_word']) - 1,1) != "{") + { + $this->p_vars['event_stack']->popEvent(); + } + } + if ($this->checkEventPop($word,$pevent)) + { + $e = $this->p_vars['event_stack']->popEvent(); + $this->p_vars['event_stack']->pushEvent($e); + if ($e == PARSER_EVENT_FUNCTION) + { + $this->wp->backupPos($word); + } + } + } + + /** + * handler for ESCAPE. + * this event handler parses "this string \"with its escape backslashes\"" and returns: + * this string "with its escape backslashes" + * to make it human-readable + */ + + function handleEscape($word, $pevent) + { + $this->p_vars['event_stack']->popEvent(); + } + + /** + * handler for COMMENT. + * this event handler parses single-line comments like: + * // this one + */ + + function handleComment($word, $pevent) + { + $this->checkEventPush( $word, $pevent); + + if (!isset($this->p_vars['comment_data'])) $this->p_vars['comment_data'] = ''; + $this->p_vars['comment_data'] .= $word; + + $this->checkEventPop($word,$pevent); + } + + /** + * handler for ARRAY. + * this event handler parses arrays in default values of function and var definitions + */ + + function handleArray($word, $pevent) + { + $e = $this->checkEventPush( $word, $pevent); + if (($e == PARSER_EVENT_COMMENTBLOCK) || + ($e == PARSER_EVENT_COMMENT)) return; + + if (!isset($this->p_vars['function_data']) || (isset($this->p_vars['function_data']) && empty($this->p_vars['function_data']))) + { + $this->p_vars['function_data'] = "array"; + } + + if ( ($this->p_vars['last_word'] == "'")) + { + $this->p_vars['function_data'] .= $this->p_vars['quote_data']."'"; + } + if ( ($this->p_vars['last_word'] == "\"")) + { + $this->p_vars['function_data'] .= $this->p_vars['quote_data']."\""; + } + + $this->p_vars['function_data'] .= $word; + //echo "function_data = |$this->p_vars['function_data']|\n"; + + if ($this->checkEventPop($word,$pevent)) + { + } + } + + /** + * handler for DEFINE. + * handles define(constant, value); statements + */ + + function handleDefine($word, $pevent) + { + if (!$this->p_flags['in_define']) + { + $this->p_vars['linenum'] = $this->wp->linenum; + } + $this->p_flags['in_define'] = true; + $this->checkEventPush( $word, $pevent); + + $this->p_flags['definename_isset'] = false; + $this->p_vars['define_params_data'] = ''; + unset($this->p_vars['quote_data']); + if ($this->checkEventPop($word,$pevent)) + { + $this->p_flags['in_define'] = false; + $this->p_vars['define'] = new parserDefine; + $this->p_vars['define']->setLineNumber($this->p_vars['linenum']); + $this->p_vars['define']->setName($this->p_vars['define_name']); + $this->p_vars['define']->setValue($this->p_vars['define_value']); + $this->publishEvent(PHPDOCUMENTOR_EVENT_DEFINE,$this->p_vars['define']); + $this->p_flags['definename_isset'] = false; + unset($this->p_vars['define']); + unset($this->p_vars['define_name']); + unset($this->p_vars['define_value']); + $this->p_flags['in_define'] = false; + $this->p_vars['define_params_data'] = ''; + } + } + + /** + * handler for DEFINE_PARAMS. + * handles the parsing of constant and value in define(constant, value); + */ + + function handleDefineParams($word, $pevent) + { + if ($this->checkEventPush( $word, $pevent)) + { + if ($word == '(') + { + $this->p_vars['define_params_data'] .= $word; + } + return; + } + + $this->p_flags['define_parens'] = true; + if(!isset($this->p_vars['define_params_data'])) $this->p_vars['define_params_data'] = ''; + + if ($this->checkEventPop($word,$pevent)) + { + if (!empty($this->p_vars['quote_data'])) + { + $this->p_vars['define_params_data'] .= $this->p_vars['quote_data']; + } + if (!empty($this->p_vars['define_params_data'])) + { + //echo $this->p_vars['define_params_data']."\n"; + $this->p_vars['define_value'] = $this->p_vars['define_params_data']; + } + else + { + if ( $this->p_vars['last_word'] != "/*" && + $this->p_vars['last_word'] != "//" && $this->p_vars['last_word'] != "#") + { + $this->p_vars['define_value'] = trim($this->p_vars['last_word']); + } + else + { + $this->p_vars['define_value'] = ""; + } + } + } + if ($this->p_flags['definename_isset']) + { + if (isset($this->p_vars['quote_data'])) + { + $this->p_vars['define_params_data'] .= '"'.$this->p_vars['quote_data'].'"'; + unset($this->p_vars['quote_data']); + } + $this->p_vars['define_params_data'] .= $word; + } else + { + if ($word != ",") + { + if (isset($this->p_vars['quote_data'])) + { + $this->p_vars['define_params_data'] .= $this->p_vars['quote_data']; + unset($this->p_vars['quote_data']); + } + $this->p_vars['define_params_data'] .= $word; + } else + { + if (isset($this->p_vars['quote_data']) && !$this->p_flags['definename_isset']) + { + $this->p_vars['define_params_data'] .= $this->p_vars['quote_data']; + unset($this->p_vars['quote_data']); + } + $this->p_flags['definename_isset'] = true; + $this->p_vars['define_name'] = $this->p_vars['define_params_data']; + unset($this->p_vars['quote_data']); + $this->p_vars['define_params_data'] = ''; + } + } + } + + /** + * handler for DEFINE_PARAMS_PARENTHESIS. + * this handler takes all parenthetical statements within constant or value in: + * define(constant, value) of a define statement, and handles them properly + */ + + function handleDefineParamsParenthesis($word, $pevent) + { + if (isset($this->p_vars['quote_data'])) + { + $this->p_vars['define_params_data'] .= '"'.$this->p_vars['quote_data'].'"'; + unset($this->p_vars['quote_data']); + } + $this->p_vars['define_params_data'] .= $word; + $this->checkEventPush( $word, $pevent); + $this->checkEventPop( $word, $pevent); + } + + /** + * handler for CLASS. + * this handler parses a class statement + */ + + function handleClass($word, $pevent) + { + $this->p_flags['in_class'] = true; + $a = $this->checkEventPush( $word, $pevent); + if ($a == PARSER_EVENT_DOCBLOCK || $a == PARSER_EVENT_DOCBLOCK_TEMPLATE) + { + $this->wp->setWhitespace(true); + } + + if (!isset($this->p_vars['class'])) $this->p_vars['class'] = false; + if (!is_subclass_of($this->p_vars['class'],"parserBase")) + { + $this->p_vars['class'] = new parserClass; + $this->p_vars['class']->setLineNumber($this->wp->linenum); + $this->p_vars['class']->setname($word); + $this->p_vars['cur_class'] = $word; + $this->p_vars['class']->setSourceLocation($this->p_vars['source_location']); + } + + if (strtolower($this->p_vars['last_word']) == "extends") + { + $this->p_vars['class']->setExtends($word); + } + + if ($word == "{") + { + $this->publishEvent(PHPDOCUMENTOR_EVENT_CLASS,$this->p_vars['class']); + } + //echo $this->wp->getPos() . ": |$word|\n"; + if ($this->checkEventPop($word,$pevent)) + { + $this->p_flags['in_class'] = false; + // throw an event when class is done + $this->publishEvent(PHPDOCUMENTOR_EVENT_NEWSTATE,STATE_END_CLASS); + $this->p_vars['class'] = false; + } + } + + /** + * handler for VAR. + * handle a var $varname = default_value; or var $varname; statement in a class definition + */ + + function handleVar($word, $pevent) + { + if (!$this->p_flags['in_var']) + { + $this->p_vars['linenum'] = $this->wp->linenum; + } + $this->p_flags['in_var'] = true; + //echo $word."\n"; + $e = $this->checkEventPush( $word, $pevent); + + if (!isset($this->p_vars['var'])) $this->p_vars['var'] = false; + if ($word == '=' || $word == ';') $this->p_flags['var_equals'] = true; + if (!$this->p_flags['var_equals']) + { + // if we haven't parsed the = yet, no arrays are possible! + if ($e == PARSER_EVENT_ARRAY) + { + $this->p_flags['arrayinvarname'] = true; + $this->p_vars['event_stack']->popEvent(); + } + if (!$e || ($e == PARSER_EVENT_ARRAY)) + $this->p_vars['varname'] .= $word; + } + + if (!$this->p_flags['var_equals']) + { + if ($word != "/*" && $word != "//" && $word != "#") + { + $this->p_vars['var'] = new parserVar($this->p_vars['cur_class']); + $this->p_vars['var']->setName($this->p_vars['varname']); + } + } + if ($this->p_vars['last_word'] == "=") + { + if ($word != "/*" && $word != "//" && $word != "#") + { + $this->p_vars['var']->setValue($word); + } + } + // fix 1202772 + if (isset($this->p_vars['quote_data']) && ($this->p_vars['last_pevent'] == PARSER_EVENT_QUOTE || $this->p_vars['last_pevent'] == PARSER_EVENT_SINGLEQUOTE)) + { + $this->p_vars['var']->setValue($this->p_vars['quote_data']); + unset($this->p_vars['quote_data']); + } + if ($this->p_vars['last_pevent'] == PARSER_EVENT_ARRAY) + { + $this->p_vars['var']->setValue($this->p_vars['function_data']); + $this->p_vars['function_data'] = false; + } + + if ($this->checkEventPop($word,$pevent)) + { + $this->p_vars['var']->setLineNumber($this->p_vars['linenum']); + $this->publishEvent(PHPDOCUMENTOR_EVENT_VAR,$this->p_vars['var']); + unset($this->p_vars['var']); + $this->p_flags['in_var'] = false; + $this->p_flags['var_equals'] = false; + $this->p_flags['arrayinvarname'] = false; + $this->p_vars['varname'] = ''; + } + } + + /** + * handler for QUOTE. + * this handler recognizes strings defined with double quotation marks (") and handles them correctly + * in any place that they legally appear in php code + */ + + function handleQuote($word, $pevent) + { + if ($this->p_flags['reset_quote_data'] === true) + { + $this->p_flags['reset_quote_data'] = false; + $this->p_vars['quote_data'] = ""; + } + $this->checkEventPush( $word, $pevent); + if ($word != "\"") + { + $this->p_vars['quote_data'] .= $word; + } + if ($this->checkEventPop($word,$pevent)) + { + $this->p_flags['reset_quote_data'] = true; + } + } + + /** + * handler for SINGLEQUOTE. + * this handler recognizes strings defined with single quotation marks (') and handles them correctly + * in any place that they legally appear in php code + */ + + function handleSingleQuote($word, $pevent) + { + $this->checkEventPush( $word, $pevent); + if ($this->checkEventPop($word,$pevent)) + { + if ($this->p_vars['last_word'] != "'") + { + $this->p_vars['quote_data'] = $this->p_vars['last_word']; + } else { + $this->p_vars['quote_data'] = ""; + } + } + } + + /** + * handler for EOFQUOTE. + * this handler recognizes strings defined with perl-style <<< EOF quotes, and handles them correctly + * in any place that they legally appear in php code + * + * an example: + * $var <<< EOF + * blah blah blah + * EOF; + */ + + function handleEOFQuote($word, $pevent) + { + // echo $this->wp->getPos() . ": word=|$word|\t\t\tlastword=|$this->p_vars['last_word']|\n"; + if (trim($this->p_vars['last_word']) == "<<<") + { + // ok we found the keyword + //echo "Keyword == $word\n"; + $this->p_vars['oldtoken'] = $this->tokens[STATE_EOFQUOTE]; + $this->tokens[STATE_EOFQUOTE] = array($word); + } + else if ($this->p_vars['last_pevent'] || PARSER_EVENT_EOFQUOTE) + { + // i don't think anything will ever use this so were not going to set it + //$this->p_vars['quote_data'] = $this->p_vars['last_word']; + $this->p_vars['event_stack']->popEvent(); + $this->tokens[STATE_EOFQUOTE] = $this->p_vars['oldtoken']; + } + } + /**#@-*/ + + /** + * Tells the parser to search for a global variable definition as + * defined by a @global type $name tag. + * + * The parser is fooled into looking for the entire global variable as a + * single token by amending the {@link $tokens} array. + * + * {@source} + * @access private + * @param string name of global variable as it appears in the source code + */ + function findGlobal($name) + { + if (!isset($this->p_vars['globaltofind'])) + { + $this->p_vars['globaltofind'] = $name; + $this->pushEvent[PARSER_EVENT_PHPCODE][strtolower($name)] = PARSER_EVENT_DEFINE_GLOBAL; + $this->tokens[STATE_PHPCODE][] = $name; + } else + { + addError(PDERROR_MULTIPLE_GLOBAL_TAGS,$this->p_vars['globaltofind'],$name); + } + } + + /**#@+ + * @access private + * @param string token parsed from source + * @param integer parser constant from {@link Parser.inc} + */ + /** + * handler for PHPCODE. + * this handler recognizes the php processor directive, and begins parsing php code + */ + + function handlePhpCode($word, $pevent) + { + $e = $this->checkEventPush( $word, $pevent); + if ($e == PARSER_EVENT_DOCBLOCK || $e == PARSER_EVENT_DOCBLOCK_TEMPLATE) + { + $this->wp->setWhitespace(true); + } + if (isset($this->p_vars['globaltofind']) && $e) + { + if ($e != PARSER_EVENT_DEFINE_GLOBAL && $e != PARSER_EVENT_ARRAY && $e != PARSER_EVENT_QUOTE && $e != PARSER_EVENT_SINGLEQUOTE && $e != PARSER_EVENT_COMMENT && $e != PARSER_EVENT_COMMENTBLOCK) + { + addError(PDERROR_GLOBAL_NOT_FOUND,$this->p_vars['globaltofind']); + unset($this->pushEvent[PARSER_EVENT_PHPCODE][strtolower($this->p_vars['globaltofind'])]); + foreach($this->tokens[STATE_PHPCODE] as $i => $notme) + if ($this->tokens[STATE_PHPCODE][$i] == $this->p_vars['globaltofind']) + unset($this->tokens[STATE_PHPCODE][$i]); + unset($this->p_vars['globaltofind']); + } + } + } + + /** + * handler for global variables + */ + function handleGlobal($word, $pevent) + { + if (!$this->p_flags['in_global']) + { + $this->p_vars['linenum'] = $this->wp->linenum; + } + $this->p_flags['in_global'] = true; + $e = $this->checkEventPush($word, $pevent); + if ($this->checkEventPop($word, $pevent)) + { + $this->p_flags['in_global'] = false; + $a = new parserGlobal; + $a->setDataType($this->p_vars['global_type']); + $this->p_vars['global_type'] = ''; + $a->setLineNumber($this->p_vars['linenum']); + $a->setName($this->p_vars['globaltofind']); + if (isset($this->p_vars['global_val'])) + $a->setValue(trim($this->p_vars['global_val'])); + unset($this->p_vars['global_val']); + $this->publishEvent(PHPDOCUMENTOR_EVENT_GLOBAL,$a); + unset($this->pushEvent[PARSER_EVENT_PHPCODE][strtolower($this->p_vars['globaltofind'])]); + foreach($this->tokens[STATE_PHPCODE] as $i => $notme) + if ($this->tokens[STATE_PHPCODE][$i] == $this->p_vars['globaltofind']) + unset($this->tokens[STATE_PHPCODE][$i]); + unset($this->p_vars['globaltofind']); + } + } + + /** + * Handles the stuff after the = in $globalvar = value + */ + function handleGlobalValue($word, $pevent) + { + if ($this->checkEventPush($word, $pevent)) + { + $this->wp->setWhitespace(false); + return; + } + if (!isset($this->p_vars['global_val'])) $this->p_vars['global_val'] = ''; + if ($this->p_vars['last_pevent'] == PARSER_EVENT_QUOTE || $this->p_vars['last_pevent'] == PARSER_EVENT_SINGLEQUOTE) + { + if (!isset($this->p_vars['quote_data'])) $this->p_vars['quote_data'] = ''; + $this->p_vars['global_val'] .= '"'.$this->p_vars['quote_data'].'"'; + unset($this->p_vars['quote_data']); + $this->p_vars['last_pevent'] = PARSER_EVENT_GLOBAL_VALUE; + } + if ($this->p_vars['last_pevent'] == PARSER_EVENT_ARRAY) + { + $this->p_vars['global_val'] .= $this->p_vars['function_data']; + $this->p_vars['function_data'] = false; + } + if ($word != ';') + $this->p_vars['global_val'] .= $word; + if ($this->checkEventPop($word, $pevent)) + { + $this->wp->setWhitespace(false); + $this->wp->backupPos($word); + } + } + + /** + * handler for FUNC_GLOBAL. + * this handler recognizes "global $var1, $var2" declarations in a function, and parses them + */ + + function handleFuncGlobal($word, $pevent) + { + if ((substr(trim($word),0,1) != '$') && ($word != ',') && ($word != ';')) + { // not a global declaration, using a variable named "$global" + $this->p_vars['event_stack']->popEvent(); + return; + } + if ($this->checkEventPop($word, $pevent)) + { + return; + } + if (!$this->checkEventPush($word, $pevent)) + { + if ($word == ',') + { // another variable + $this->p_vars['global_count']++; + } else + { + if (!isset($this->p_vars['globals'][$this->p_vars['global_count']])) + $this->p_vars['globals'][$this->p_vars['global_count']] = ''; + if (!empty($this->p_vars['globals'][$this->p_vars['global_count']])) $this->p_vars['global_count']++; + $this->p_vars['globals'][$this->p_vars['global_count']] = trim($word); + } + } + } + + /** + * handler for STATIC_VAR. + * this handler recognizes "static $var1, $var2 = 6" declarations in a function, and parses them + */ + + function handleStaticVar($word, $pevent) + { + if ($this->checkEventPop($word, $pevent)) + { + $this->p_vars['static_count']++; + return; + } + if (!$this->checkEventPush($word, $pevent)) + { + if ($word == ',') + { + $this->p_vars['static_count']++; + return; + } + if (!isset($this->p_vars['statics'][$this->p_vars['static_count']])) + $this->p_vars['statics'][$this->p_vars['static_count']] = ''; + if (!empty($this->p_vars['statics'][$this->p_vars['static_count']])) $this->p_vars['static_count']++; + $this->p_vars['statics'][$this->p_vars['static_count']] = trim($word); + } + } + + /** + * handler for STATIC_VAR_VALUE. + * this handler parses the 6 in "static $var1, $var2 = 6" + */ + + function handleStaticValue($word, $pevent) + { + if ($this->checkEventPush($word, $pevent)) + { + return; + } + if (!isset($this->p_vars['static_val'][$this->p_vars['static_count']])) $this->p_vars['static_val'][$this->p_vars['static_count']] = ''; + if ($this->p_vars['last_pevent'] == PARSER_EVENT_QUOTE || $this->p_vars['last_pevent'] == PARSER_EVENT_SINGLEQUOTE) + { + $this->p_vars['static_val'][$this->p_vars['static_count']] .= '"'.$this->p_vars['quote_data'].'"'; + unset($this->p_vars['quote_data']); + } + if ($this->p_vars['last_pevent'] == PARSER_EVENT_ARRAY) + { + $this->p_vars['static_val'][$this->p_vars['static_count']] .= $this->p_vars['function_data']; + $this->p_vars['function_data'] = false; + } + if ($this->checkEventPop($word, $pevent)) + { + $this->p_vars['static_val'][$this->p_vars['static_count']] = trim($this->p_vars['static_val'][$this->p_vars['static_count']]); + $this->wp->backupPos($word); + return; + } else $this->p_vars['static_val'][$this->p_vars['static_count']] .= $word; + } + + /** + * handler for FUNCTION. + * this handler recognizes function declarations, and parses them. The body + * of the function is parsed by handleLogicBlock() + * @see handleLogicBlock() + */ + + function handleFunction($word, $pevent) + { + if ($e = $this->checkEventPush( $word, $pevent)) + { + if ($e == PARSER_EVENT_COMMENT || $e == PARSER_EVENT_COMMENTBLOCK) return; + } + + if (!isset($this->p_vars['func'])) $this->p_vars['func'] = false; + if (! is_subclass_of($this->p_vars['func'],"parserBase")) + { + $this->p_vars['globals'] = array(); + $this->p_vars['global_count'] = 0; + if ($this->p_flags['in_class']) + $this->p_vars['func'] = new parserMethod($this->p_vars['cur_class']); + else + $this->p_vars['func'] = new parserFunction; + $this->p_vars['func']->setLineNumber($this->wp->linenum); + if (trim($word) != '&') + $this->p_vars['func']->setName(trim($word)); + else + $this->p_vars['func']->setReturnsReference(); + } else + { + if ($this->p_vars['func']->getReturnsReference()) + { + if ($this->p_vars['last_word'] == '&') + { + $this->p_vars['func']->setName(trim($word)); + } + } + } + if ($this->checkEventPop($word,$pevent)) + { + $this->p_vars['func']->addGlobals($this->p_vars['globals']); + $this->p_vars['func']->addStatics($this->p_vars['statics'],$this->p_vars['static_val']); + $this->p_vars['globals'] = array(); + $this->p_vars['global_count'] = 0; + if ($this->p_flags['getting_source']) + { + $x = $this->wp->getSource(); + $this->p_vars['func']->addSource($x); + $this->p_flags['get_source'] = false; + $this->p_flags['getting_source'] = false; + } + $this->publishEvent(PHPDOCUMENTOR_EVENT_FUNCTION,$this->p_vars['func']); + $this->p_vars['func'] = false; + } + } + + /**#@-*/ + /** + * Helper function for {@link handleFunctionParams()} + * + * This function adds a new parameter to the parameter list + * @access private + * @param string + */ + function endFunctionParam($word) + { + if (isset($this->p_vars['quote_data']) && ($this->p_vars['last_pevent'] == PARSER_EVENT_SINGLEQUOTE)) + { + $this->p_vars['function_data'] .= "'".$this->p_vars['quote_data']."'"; + unset($this->p_vars['quote_data']); + } + if (isset($this->p_vars['quote_data']) && ($this->p_vars['quote_data'] != '') && ($this->p_vars['last_pevent'] == PARSER_EVENT_QUOTE)) + { + $this->p_vars['function_data'] .= '"'.$this->p_vars['quote_data'].'"'; + unset($this->p_vars['quote_data']); + } + if (isset($this->p_vars['function_param'])) + { + $this->p_vars['func']->addParam($this->p_vars['function_param'],$this->p_vars['function_data'], $this->p_flags['funcparam_val']); + unset($this->p_vars['function_param']); + $this->p_vars['function_data'] = ''; + $this->p_flags['funcparam_val'] = false; + } + } + /**#@+ + * @access private + * @param string token parsed from source + * @param integer parser constant from {@link Parser.inc} + */ + /** + * handler for FUNCTION_PARAMS. + * this handler recognizes the parameters of a function within parentheses like function(param, param = default_value) + * and parses them + * @see endFunctionParam() + */ + + function handleFunctionParams($word, $pevent) + { + //echo $this->wp->getPos() . ": word=|$word|\t\t\tlastword=|".$this->p_vars['last_word']."|\n"; + //echo "function_param = '".$this->p_vars['function_param']."'\n"; + //echo "function_data = '".$this->p_vars['function_data']."'\n"; + $e1 = $this->checkEventPush( $word, $pevent); + + if (!$e1) + { + if ($word == ',' || $this->checkEventPop($word,$pevent)) + { + $this->endFunctionParam($word); + } elseif ($word == '=') + { + $this->p_flags['funcparam_val'] = true; + } else + { + if ($this->p_flags['funcparam_val']) + { + if (isset($this->p_vars['quote_data']) && ($this->p_vars['last_pevent'] == PARSER_EVENT_SINGLEQUOTE)) + { + $this->p_vars['function_data'] .= "'".$this->p_vars['quote_data']."'"; + unset($this->p_vars['quote_data']); + } + if (isset($this->p_vars['quote_data']) && ($this->p_vars['last_pevent'] == PARSER_EVENT_QUOTE)) + { + $this->p_vars['function_data'] .= '"'.$this->p_vars['quote_data'].'"'; + unset($this->p_vars['quote_data']); + } + $this->p_vars['function_data'] .= $word; + } else + { + $this->p_vars['function_param'] = $word; + } + } + } + } + + + /** + * javadoc-desc-compliant handler for DOCBLOCK. + * this handler recognizes @tags in DocBlocks and parses them for display. + * It also parses out unknown tags into their own array for use by the docblock + */ + + function JavaDochandleDocblock($word, $pevent) + { + $e1 = $this->checkEventPush( $word, $pevent); + if (!isset($this->p_vars[$this->p_vars['docblock_type']]) || !$this->p_vars[$this->p_vars['docblock_type']]) + { + $this->p_vars[$this->p_vars['docblock_type']] = new parserDocBlock(); + $this->p_vars['returntype'] = false; + $this->p_vars['vartype'] = false; + $this->p_flags['startdocblock'] = true; + $this->p_flags['valid_newline'] = true; + $this->p_flags['startline'] = true; + $this->p_flags['newline'] = true; + $this->p_flags['in_desc'] = true; + $this->p_flags['in_tag'] = false; + $this->p_flags['useperiod'] = false; + $this->p_vars['line'] = array(); + $this->p_vars['linecount'] = 0; + } + $e = $this->checkEventPop( $word, $pevent); + if (!$e1 && !$e) + { + if ($this->p_flags['in_desc']) $this->JavaDochandleDesc($word, $pevent); + else $this->handleTags($word, $pevent); + } + if ($e) + { + if (!isset($this->p_vars['periodline'])) $this->p_vars['periodline'] = 0; + if ($this->p_vars['periodline'] > 3) + { + $this->p_flags['useperiod'] = false; + } + + $this->p_vars['docblock_desc'] = new parserDesc; +// echo "i = ".$this->p_vars['periodline']."; i < " . count($this->p_vars['line']) . "\n"; + if ($this->p_vars['docblock_type'] == 'docblock') + { + if (isset($this->p_vars['docblock_template'])) + { + // copy template values if not overridden + if (!$this->p_vars['docblock']->getExplicitPackage()) + { + if ($p = $this->p_vars['docblock_template']->getKeyword('package')) + { + $this->p_vars['docblock']->addKeyword('package',$p); + $this->p_vars['docblock']->setExplicitPackage(); + } + if ($p = $this->p_vars['docblock_template']->getKeyword('category')) + { + $this->p_vars['docblock']->addKeyword('category',$p); + $this->p_vars['docblock']->setExplicitCategory(); + } + if ($p = $this->p_vars['docblock_template']->getKeyword('subpackage')) + { + $this->p_vars['docblock']->addKeyword('subpackage',$p); + } + } + $tags = $this->p_vars['docblock_template']->listTags(); + foreach($tags as $tag) + { + $this->p_vars['docblock']->addKeyword($tag->keyword,$tag->value); + } + $this->p_vars['docblock_desc']->add($this->p_vars['docblock_template']->desc); + if (!count($this->p_vars['docblock']->params)) $this->p_vars['docblock']->params = $this->p_vars['docblock_template']->params; + } + if ($a = strpos(trim($this->p_vars['shortdesc']),'

            ') === 0) + $this->p_vars['shortdesc'] = substr($this->p_vars['shortdesc'],strpos($this->p_vars['shortdesc'],'

            ') + 4); + $this->p_vars[$this->p_vars['docblock_type']]->setShortDesc($this->p_vars['shortdesc']); + } + for($i = 0; $i < count($this->p_vars['line']); $i++) + { + // the line will not be set if it doesn't start with a * + if (isset($this->p_vars['line'][$i])) + $this->p_vars['docblock_desc']->add($this->p_vars['line'][$i]); + } + + + $this->p_vars[$this->p_vars['docblock_type']]->setDesc($this->p_vars['docblock_desc']); + unset($this->p_vars['docblock_desc']); +// var_dump($this->p_vars[$this->p_vars['docblock_type']]); +// exit; + if ($this->p_vars['docblock_type'] == 'docblock') + { + $this->publishEvent(PHPDOCUMENTOR_EVENT_DOCBLOCK,$this->p_vars[$this->p_vars['docblock_type']]); + unset($this->p_vars[$this->p_vars['docblock_type']]); + $this->p_vars[$this->p_vars['docblock_type']] = new parserDocBlock(); + } + $this->p_flags['in_desc'] = true; + $this->p_flags['in_tag'] = false; + $this->p_flags['useperiod'] = false; + $this->p_vars['line'] = array(); + $this->p_vars['linecount'] = 0; + $this->p_flags['start_docblock'] = true; + $this->p_flags['valid_newline'] = true; + $this->wp->setWhitespace(false); + } + } + + /** + * handler for DOCKEYWORD_DESC. + * this handler parses the short and long description of a dockeyword + */ + + function JavaDochandleDesc($word, $pevent) + { + if ($this->p_flags['valid_newline']) + { + if ($word == '@' && $this->p_flags['startline']) + { + return $this->handleTag($word, $pevent); + } + if (!isset($this->p_vars['line'][$this->p_vars['linecount']])) + { + $this->p_vars['line'][$this->p_vars['linecount']] = new parserStringWithInlineTags; + } + if ($this->p_vars['last_word'] == "." && $this->p_flags['useperiod'] == false) + { + $this->p_vars['periodline'] = $this->p_vars['linecount']; + $this->p_vars['shortdesc'] = new parserDesc; + for($i = 0; ($i <= $this->p_vars['periodline']) && ($i < count($this->p_vars['line'])); $i++) + { + if (isset($this->p_vars['line'][$i])) + $this->p_vars['shortdesc']->add($this->p_vars['line'][$i]); + } + $this->p_flags['useperiod'] = true; + } + $this->p_vars['line'][$this->p_vars['linecount']]->add($word); +// debug("DESC $word"); + } + $this->handleCR($word); + } + + /** + * handler for DOCBLOCK. + * this handler recognizes @tags in DocBlocks and parses them for display. + * It also parses out unknown tags into their own array for use by the docblock + */ + + function BetterhandleDocblock($word, $pevent) + { + $e1 = $this->checkEventPush( $word, $pevent); + if (!$this->wp->returnWhiteSpace) + { + addErrorDie(PDERROR_NEED_WHITESPACE); + } + if (!isset($this->p_vars[$this->p_vars['docblock_type']]) || !$this->p_vars[$this->p_vars['docblock_type']]) + { + $this->p_vars[$this->p_vars['docblock_type']] = new parserDocBlock(); + $this->p_vars['returntype'] = false; + $this->p_vars['vartype'] = false; + $this->p_flags['startdocblock'] = true; + $this->p_flags['valid_newline'] = true; + $this->p_flags['startline'] = true; + $this->p_flags['newline'] = true; + $this->p_flags['in_desc'] = true; + $this->p_flags['in_tag'] = false; + $this->p_flags['useperiod'] = false; + $this->p_vars['line'] = array(); + $this->p_vars['linecount'] = 0; + } + $e = $this->checkEventPop( $word, $pevent); + if (!$e1 && !$e) + { + if ($this->p_flags['in_desc']) $this->handleDesc($word, $pevent); + else $this->handleTags($word, $pevent); + } + if ($e) + { + if (!isset($this->p_vars['periodline'])) $this->p_vars['periodline'] = 0; + if ($this->p_vars['periodline'] > 3) + { + $this->p_flags['useperiod'] = false; + } else + { + for($i = 0; $i < $this->p_vars['periodline']; $i++) + { + if (isset($this->p_vars['line'][$i])) + { + if ($this->p_vars['line'][$i]->trimmedStrlen() == 0 && isset($this->p_vars['line'][$i - 1]) && $this->p_vars['line'][$i - 1]->trimmedStrlen()) + { + $this->p_vars['periodline'] = $i; + } + } + } + } + // figure out the shortdesc + if ($this->p_flags['useperiod'] === false) + { + // use the first non blank line for short desc + for($i = 0; $i < count($this->p_vars['line']); $i++) + { + if (!isset($this->p_vars['line'][$i])) + $this->p_vars['line'][$i] = new parserStringWithInlineTags; + if ($this->p_vars['line'][$i]->trimmedStrlen() > 0) + { + $this->p_vars['periodline'] = $i; + $i = count($this->p_vars['line']); + } + } + + // check to see if we are going to use a blank line to end the shortdesc + // this can only be in the first 4 lines + if (count($this->p_vars['line']) > 4) + { + $max = 4; + } else { + $max = count($this->p_vars['line']); + } + + for($i = $this->p_vars['periodline']; $i < $max; $i++) + { + if (isset($this->p_vars['line'][$i])) + if ($this->p_vars['line'][$i]->trimmedStrlen() == 0) + { + $this->p_vars['periodline'] = $i; + $i = $max; + } + } + } + + if ($this->p_vars['docblock_type'] == 'docblock') + { + $this->p_vars['shortdesc'] = new parserDesc; + for($i = 0; ($i <= $this->p_vars['periodline']) && ($i < count($this->p_vars['line'])); $i++) + { + if (isset($this->p_vars['line'][$i])) + $this->p_vars['shortdesc']->add($this->p_vars['line'][$i]); + } + $this->p_vars['periodline']++; + + $this->p_vars['docblock_desc'] = new parserDesc; + if (isset($this->p_vars['docblock_template'])) + { + // copy template values if not overridden + if (!$this->p_vars['docblock']->getExplicitPackage()) + { + if ($p = $this->p_vars['docblock_template']->getKeyword('package')) + { + $this->p_vars['docblock']->addKeyword('package',$p); + $this->p_vars['docblock']->setExplicitPackage(); + } + if ($p = $this->p_vars['docblock_template']->getKeyword('category')) + { + $this->p_vars['docblock']->addKeyword('category',$p); + $this->p_vars['docblock']->setExplicitCategory(); + } + if ($p = $this->p_vars['docblock_template']->getKeyword('subpackage')) + { + $this->p_vars['docblock']->addKeyword('subpackage',$p); + } + } + $tags = $this->p_vars['docblock_template']->listTags(); + foreach($tags as $tag) + { + $this->p_vars['docblock']->addKeyword($tag->keyword,$tag->value); + } + if (!count($this->p_vars['docblock']->params)) $this->p_vars['docblock']->params = $this->p_vars['docblock_template']->params; + $this->p_vars['docblock_desc']->add($this->p_vars['docblock_template']->desc); + } + // echo "i = ".$this->p_vars['periodline']."; i < " . count($this->p_vars['line']) . "\n"; + for($i = $this->p_vars['periodline']; $i < count($this->p_vars['line']); $i++) + { + // the line will not be set if it doesn't start with a * + if (isset($this->p_vars['line'][$i])) + $this->p_vars['docblock_desc']->add($this->p_vars['line'][$i]); + } + } else + { + $this->p_vars['shortdesc'] = new parserDesc; + for($i = 0; ($i <= $this->p_vars['periodline']) && ($i < count($this->p_vars['line'])); $i++) + { + if (isset($this->p_vars['line'][$i])) + $this->p_vars['shortdesc']->add($this->p_vars['line'][$i]); + } + $this->p_vars['periodline']++; + + $this->p_vars['docblock_desc'] = new parserDesc; + for($i=$this->p_vars['periodline']; $i < count($this->p_vars['line']); $i++) + { + if (isset($this->p_vars['line'][$i])) + $this->p_vars['docblock_desc']->add($this->p_vars['line'][$i]); + } + } + + + $this->p_vars[$this->p_vars['docblock_type']]->setShortDesc($this->p_vars['shortdesc']); + $this->p_vars[$this->p_vars['docblock_type']]->setDesc($this->p_vars['docblock_desc']); + unset($this->p_vars['docblock_desc']); +// var_dump($this->p_vars[$this->p_vars['docblock_type']]); +// exit; + if ($this->p_vars['docblock_type'] == 'docblock') + { + $this->publishEvent(PHPDOCUMENTOR_EVENT_DOCBLOCK,$this->p_vars[$this->p_vars['docblock_type']]); + unset($this->p_vars[$this->p_vars['docblock_type']]); + $this->p_vars[$this->p_vars['docblock_type']] = new parserDocBlock(); + } else + { + $this->publishEvent(PHPDOCUMENTOR_EVENT_DOCBLOCK_TEMPLATE,$this->p_vars[$this->p_vars['docblock_type']]); + } + $this->p_flags['in_desc'] = true; + $this->p_flags['in_tag'] = false; + $this->p_flags['useperiod'] = false; + $this->p_vars['line'] = array(); + $this->p_vars['linecount'] = 0; + $this->p_flags['start_docblock'] = true; + $this->p_flags['valid_newline'] = true; + $this->wp->setWhitespace(false); + $this->p_vars['docblock_type'] = 'docblock'; + } + } + + /** + * Handles docblock templates + * @tutorial phpDocumentor.howto.pkg#basics.docblocktemplate + */ + function handleDocBlockTemplate($word, $pevent) + { + $this->p_vars['docblock_type'] = 'docblock_template'; + $this->p_vars['event_stack']->popEvent(); + $this->p_vars['event_stack']->pushEvent(PARSER_EVENT_DOCBLOCK); + // fool the docblock handler into thinking everything is totally normal + $this->p_vars['last_word'] = '/**'; + $pevent = PARSER_EVENT_DOCBLOCK; + $this->BetterhandleDocBlock($word, $pevent); + } + + /** + * Handles closing docblock templates /**#@-* / + * @tutorial phpDocumentor.howto.pkg#basics.docblocktemplate + */ + function handleEndDocBlockTemplate($word, $pevent) + { + unset($this->p_vars['docblock_template']); + $this->publishEvent(PHPDOCUMENTOR_EVENT_NEWSTATE,PHPDOCUMENTOR_EVENT_END_DOCBLOCK_TEMPLATE); + $this->p_vars['event_stack']->popEvent(); + } + /**#@-*/ + /** + * Handles a new line in a DocBlock + * @param string token containing a newline \n + * @access private + */ + function handleCR($word) + { + $this->laststart = $this->p_flags['startline']; + if ($word == "\n" || $word == ".\n") + { + $this->p_flags['start_docblock'] = false; + $this->p_flags['newline'] = true; + $this->p_flags['valid_newline'] = false; + if ($this->p_flags['in_desc'] && !$this->p_flags['useperiod']) + { + if ($word == ".\n") + { + $this->p_flags['useperiod'] = true; + $this->p_vars['periodline'] = $this->p_vars['linecount']; + } + } + } else + { + if ($this->p_flags['valid_newline'] && strlen(trim($word))) + { + $this->p_flags['startline'] = false; + } + if ($this->p_flags['newline'] && ($word == '*' || $this->p_flags['start_docblock'])) + { + $this->p_flags['newline'] = false; + $this->p_flags['valid_newline'] = true; + if (!$this->p_flags['start_docblock']) + $this->p_vars['linecount']++; + $this->p_flags['startline'] = true; + $justset = true; +// debug('valid newline'); + } + } + } + + /** + * handler for DOCKEYWORD_DESC. + * this handler parses the short and long description of a dockeyword + * @access private + */ + + function handleDesc($word, $pevent) + { +// echo "|$word|\n"; + if ($this->p_flags['valid_newline']) + { + if ($word == '@' && $this->p_flags['startline']) + { + return $this->handleTag($word, $pevent); + } + if ($this->p_vars['last_word'] == ". " || $this->p_vars['last_word'] == ".\t") + { + $this->p_flags['useperiod'] = true; + $this->p_vars['periodline'] = $this->p_vars['linecount']; + $this->p_vars['linecount']++; + } + if (!isset($this->p_vars['line'][$this->p_vars['linecount']])) + { + $this->p_vars['line'][$this->p_vars['linecount']] = new parserStringWithInlineTags; + } + if ($this->p_flags['startline']) + { + if ($word[0] == ' ') $word = substr($word,1); +// $word = ltrim($word," \t"); + } + if ($word != '') $this->p_vars['line'][$this->p_vars['linecount']]->add($word); +// debug("DESC $word"); + } + $this->handleCR($word); + } + + /**#@+ + * @access private + * @param string token parsed from source + * @param integer parser constant from {@link Parser.inc} + */ + /** + * handler for DOCKEYWORD_TAGS. + * this handler recognizes @tags in DocBlocks and parses them for display + * I think this may be unused. We'll delete from 1.1 if so + */ + function handleTags($word, $pevent) + { + if ($this->p_flags['valid_newline']) + { +// debug("TAGS $word"); + } + $this->handleCR($word); + } + + /** + * handler for DOCKEYWORD. + * this handler recognizes @tags in DocBlocks and parses them for display + */ + function handleTag($word, $pevent) + { + if ($this->p_flags['in_desc'] && !$this->p_flags['valid_newline']) + { + $this->p_vars['event_stack']->popEvent(); + return $this->handleDesc($word, $pevent); + } +// if ($this->p_vars['last_word'] == '@') fancy_debug('here'.$word,$this->p_flags['startline'],$this->p_flags['in_tag']); + if ($this->p_vars['tagname'] == 'author') + { + if ($word == '<') + { + $this->p_vars['event_stack']->pushEvent(PARSER_EVENT_DOCKEYWORD_EMAIL); + return $this->handleDockeywordEmail($word, $pevent); + } + } + if ($this->checkEventPush( $word, $pevent)) return; + if ($this->p_vars['last_word'] == '@' && !$this->p_flags['startline'] && $this->p_flags['in_desc']) + { + // fix 1203445 + if (!isset($this->p_vars['line'][$this->p_vars['linecount']])) + { + $this->p_vars['line'][$this->p_vars['linecount']] = new parserStringWithInlineTags; + } + $this->p_vars['event_stack']->popEvent(); + $this->p_vars['line'][$this->p_vars['linecount']]->add('@'); + return $this->handleDesc($word, $pevent); + } elseif($this->p_vars['last_word'] == '@' && !strlen(trim($word)) && empty($this->p_vars['tagname']) && $this->p_flags['in_desc']) + { + // fix 1203445 + if (!isset($this->p_vars['line'][$this->p_vars['linecount']])) + { + $this->p_vars['line'][$this->p_vars['linecount']] = new parserStringWithInlineTags; + } + $pevent = $this->p_vars['event_stack']->popEvent(); + $this->p_vars['line'][$this->p_vars['linecount']]->add('@'); + return $this->handleDesc($word, $pevent); + } + if ($word == '@' && $this->p_flags['startline'] && $this->p_flags['in_tag']) + { + $this->wp->backupPos($word); + $white = $this->wp->returnWhiteSpace; + $this->wp->setWhitespace(true); + $word1 = $this->wp->getWord(); + $this->wp->backupPos($word1); + if (strlen(trim($word1))) + { + $this->endTag(); + } + $this->wp->getWord(); + $this->wp->setWhitespace($white); + } + $this->p_flags['in_tag'] = true; + $e = $this->checkEventPop($word, $pevent); + if (!$e) + { + if ($this->p_flags['valid_newline']) + { + if (($this->p_flags['startline'] || $this->laststart) && $word != '@') + { + if ($this->p_vars['last_word'] == '@') + { +// debug("TAGSTART $word"); + $this->p_flags['in_tag'] = true; + $this->p_vars['tagname'] = $word; + $this->p_flags['startline'] = false; + $this->p_vars['tag_value'] = new parserStringWithInlineTags; + } else + { +// debug("TAG1 $word"); + if (isset($this->tagHandlers[$this->p_vars['tagname']])) + $handler = $this->tagHandlers[$this->p_vars['tagname']]; + else $handler = $this->tagHandlers['*']; + $this->$handler($word); + } + } else + { + if (empty($this->p_vars['tagname'])) + { + if ($this->p_flags['in_desc']) + { + $this->p_flags['in_tag'] = false; + // fix 1203445 + if (!isset($this->p_vars['line'][$this->p_vars['linecount']])) + { + $this->p_vars['line'][$this->p_vars['linecount']] = + new parserStringWithInlineTags; + } + $this->p_vars['line'][$this->p_vars['linecount']]->add('@'); + $this->p_vars['event_stack']->popEvent(); + $this->handleCR($word); + return $this->handleDesc($word, $pevent); + } + } +// debug("TAG2 $word"); + if (isset($this->tagHandlers[$this->p_vars['tagname']])) + $handler = $this->tagHandlers[$this->p_vars['tagname']]; + else $handler = $this->tagHandlers['*']; + $this->$handler($word); + } + } + $this->handleCR($word); + } + $this->p_flags['in_desc'] = false; + if ($e) + { + $this->endTag(); + $this->wp->setWhitespace(false); + // walk back a word + $this->wp->backupPos($word); + $this->wp->setWhitespace(true); + } + } + /**#@-*/ + /** + * Called to clean up at the end of parsing a @tag in a docblock + */ + function endTag() + { + if (isset($this->tagHandlers[$this->p_vars['tagname']])) + $handler = $this->tagHandlers[$this->p_vars['tagname']]; + else $handler = $this->tagHandlers['*']; + $this->$handler(false); + $this->p_vars['tagname'] = ''; + $this->p_flags['startline'] = true; +// debug("ENDTAG"); + } + + /**#@+ + * Tag Handlers + * @param string + */ + /** + * Handles all standard tags that only have a description + */ + function defaultTagHandler($word) + { + if ($word !== false) + { + $this->p_vars['tag_value']->add($word); + } else + { + $this->p_vars[$this->p_vars['docblock_type']]->addKeyword($this->p_vars['tagname'],$this->p_vars['tag_value']); + } + } + + /** + * Handles tags like '@filesource' that only work in PHP 4.3.0+ + */ + function invalidTagHandler($word) + { + if ($word === false) + { + addError(PDERROR_TAG_NOT_HANDLED,$this->p_vars['tagname']); + } + } + + /** + * handles @package + * @tutorial tags.package.pkg + */ + function packageTagHandler($word) + { + if ($word !== false) + { + $this->p_vars['tag_value']->add($word); + } else + { + $this->p_vars[$this->p_vars['docblock_type']]->addKeyword($this->p_vars['tagname'],$this->p_vars['tag_value']); + $this->p_vars[$this->p_vars['docblock_type']]->setExplicitPackage(); + } + } + + /** + * handles @example + * @tutorial tags.example.pkg + */ + function exampleTagHandler($word) + { + if ($word !== false) + { + $this->p_vars['tag_value']->add($word); + } else + { + $this->p_vars[$this->p_vars['docblock_type']]->addExample($this->p_vars['tag_value'], $this->p_vars['parsepath']); + } + } + + /** + * handles @category + * @tutorial tags.category.pkg + */ + function categoryTagHandler($word) + { + if ($word !== false) + { + $this->p_vars['tag_value']->add($word); + } else + { + $this->p_vars[$this->p_vars['docblock_type']]->addKeyword($this->p_vars['tagname'],$this->p_vars['tag_value']); + $this->p_vars[$this->p_vars['docblock_type']]->setExplicitCategory(); + } + } + + /** + * handles @global + * @tutorial tags.global.pkg + */ + function globalTagHandler($word) + { + if ($word !== false) + { + // no data yet + $a = trim($this->p_vars['tag_value']->getString()); + if (empty($a)) + { + // not an empty word + if (trim($word) != '') + { + if (!empty($this->p_vars['global_type'])) + { + if (!$this->p_flags['define_global'] && !$this->p_flags['function_global']) + { + // @global type $GLOBALVARNAME ? + if (substr($word,0,1) == '$') + { + $this->p_flags['define_global'] = true; + $this->p_flags['function_global'] = false; + $this->p_vars['find_global'] = $word; + } else + { // function @global type description + $this->p_flags['function_global'] = true; + $this->p_flags['define_global'] = false; + $this->p_vars['tag_value']->add($word); + } + } else + { + if ($this->p_flags['define_global']) + { + $this->p_vars['find_global'] .= $word; + } elseif($this->p_flags['function_global']) + { + // description, to be added to the tag + $this->p_vars['tag_value']->add($word); + } + } + } else + { + $this->p_vars['global_type'] = $word; + } + } else $this->p_vars['tag_value']->add($word); // add whitespace to the tag description + } else + { // tag_value has data, must be a function @global + $this->p_vars['tag_value']->add($word); + } + } else + { // endtag + if ($this->p_flags['define_global']) + { + $this->findGlobal($this->p_vars['find_global']); + } + elseif ($this->p_flags['function_global']) + { + $this->p_vars[$this->p_vars['docblock_type']]->addFuncGlobal($this->p_vars['global_type'],$this->p_vars['tag_value']); + $this->p_vars['global_type'] = ''; + } + else + { + addError(PDERROR_MALFORMED_GLOBAL_TAG); + } + $this->p_vars['find_global'] = ''; + $this->p_flags['define_global'] = false; + $this->p_flags['function_global'] = false; + } + } + + /** + * handles @staticvar + * @tutorial tags.staticvar.pkg + */ + function staticvarTagHandler($word) + { + if ($word !== false) + { + if (!$this->p_vars['returntype']) $this->p_vars['returntype'] = trim($word); + else + { + if (!$this->p_vars['paramname']) + { + if (substr(trim($word),0,1) == "$") + $this->p_vars['paramname'] = trim($word); + else $this->p_vars['tag_value']->add($word); + } else + { + if (0)//strtolower($this->p_vars['paramtype']) == 'object') + { + if (strlen(trim($word))) + $this->p_vars['paramname'] = trim($word); + } else $this->p_vars['tag_value']->add($word); + } + } + } else + { + if (!$this->p_vars['paramname']) + $this->p_vars[$this->p_vars['docblock_type']]->addStaticVar(null,$this->p_vars['returntype'],$this->p_vars['tag_value']); + else + $this->p_vars[$this->p_vars['docblock_type']]->addStaticVar($this->p_vars['paramname'],$this->p_vars['returntype'],$this->p_vars['tag_value']); + $this->p_vars['paramname'] = false; + $this->p_vars['returntype'] = false; + } + } + + /** + * handles @uses + * @tutorial tags.uses.pkg + */ + function usesTagHandler($word) + { + if ($word !== false) + { + if (!$this->p_vars['seelement']) $this->p_vars['seelement'] = trim($word); + else + { + $this->p_vars['tag_value']->add($word); + } + } else + { + $see = new parserStringWithInlineTags; + $see->add($this->p_vars['seelement']); + $this->p_vars[$this->p_vars['docblock_type']]->addUses($see,$this->p_vars['tag_value']); + $this->p_vars['seelement'] = false; + } + } + + /** + * handles @param + * @tutorial tags.param.pkg + */ + function paramTagHandler($word) + { + if ($word !== false) + { + if (!$this->p_vars['returntype']) $this->p_vars['returntype'] = trim($word); + else + { + if (!$this->p_vars['paramname']) + { + if (substr(trim($word),0,1) == "$" || substr(trim($word),0,2) == "&$") + $this->p_vars['paramname'] = trim($word); + else $this->p_vars['tag_value']->add($word); + } else + { + if (0)//strtolower($this->p_vars['paramtype']) == 'object') + { + if (strlen(trim($word))) + $this->p_vars['paramname'] = trim($word); + } else $this->p_vars['tag_value']->add($word); + } + } + } else + { + if (!$this->p_vars['paramname']) + $this->p_vars[$this->p_vars['docblock_type']]->addParam(null,$this->p_vars['returntype'],$this->p_vars['tag_value']); + else + $this->p_vars[$this->p_vars['docblock_type']]->addParam($this->p_vars['paramname'],$this->p_vars['returntype'],$this->p_vars['tag_value']); + $this->p_vars['paramname'] = false; + $this->p_vars['returntype'] = false; + } + } + + /** + * handles @return + * @tutorial tags.return.pkg + */ + function returnTagHandler($word) + { + if ($word !== false) + { + if (!$this->p_vars['returntype']) $this->p_vars['returntype'] = trim($word); + else + { + if (strtolower($this->p_vars['returntype']) == 'object') + { + if (strlen(trim($word))) + $this->p_vars['returntype'] = trim($word); + } else $this->p_vars['tag_value']->add($word); + } + } else + { + $this->p_vars[$this->p_vars['docblock_type']]->addReturn($this->p_vars['returntype'],$this->p_vars['tag_value']); + $this->p_vars['returntype'] = false; + } + } + + /** + * handles @var + * @tutorial tags.var.pkg + */ + function varTagHandler($word) + { + if ($word) + { + if (!$this->p_vars['vartype']) $this->p_vars['vartype'] = trim($word); + else + { + if (strtolower($this->p_vars['vartype']) == 'object') + { + if (strlen(trim($word))) + $this->p_vars['vartype'] = trim($word); + } + else $this->p_vars['tag_value']->add($word); + } + } elseif ($word === false) + { + $this->p_vars[$this->p_vars['docblock_type']]->addVar($this->p_vars['vartype'],$this->p_vars['tag_value']); + $this->p_vars['vartype'] = false; + } + } + /**#@-*/ + /** @access private */ + function getSource() + { + $this->p_flags['get_source'] = true; + } + /**#@+ + * @access private + * @param string token parsed from source + * @param integer parser constant from {@link Parser.inc} + */ + /** + * handler for DOCKEYWORD_EMAIL. + * this handler recognizes angle brackets < and > surrounding an email address in an @author tag, + * and returns a mailto: hyperlink + */ + + function handleDockeywordEmail($word, $pevent) + { + //echo $this->wp->getPos() . ": |$word|\n"; + if (!$this->checkEventPop($word,$pevent) && $word != "<") + { + if (strstr($word,"@")) + { + $this->p_vars['tag_value']->add('<'); + $this->p_vars['tag_value']->add(new parserLinkInlineTag("mailto:$word",$word)); + $this->p_vars['tag_value']->add('>'); + } else { + $this->p_vars['tag_value']->add("<$word>"); + } + } + } + + /** + * handler for INLINE_DOCKEYWORD. + * this handler recognizes {@inline tags} like link, and parses them, replacing them directly + * in the text flow with their output. + */ + + function handleInlineDockeyword($word, $pevent) + { + // echo $this->wp->getPos() . ": |$word|\n"; + + // echo "docktype: $this->p_vars['inline_dockeyword_type']\n"; + if (!isset($this->p_vars['inline_dockeyword_type'])) $this->p_vars['inline_dockeyword_type'] = false; + if (!isset($this->p_vars['inline_dockeyword_data'])) $this->p_vars['inline_dockeyword_data'] = ''; + if (!$this->p_vars['inline_dockeyword_type']) + { + if (in_array($word,$this->allowableInlineTags)) + { + if ($word == '}') + $this->p_vars['inline_dockeyword_type'] = ''; + else + $this->p_vars['inline_dockeyword_type'] = strtolower($word); + $this->p_vars['whitesp'] = $this->wp->returnWhiteSpace; + $this->wp->setWhiteSpace(true); + } else { + if ($this->p_flags['in_desc']) + { + // fix 1203445 + if (!isset($this->p_vars['line'][$this->p_vars['linecount']])) + { + $this->p_vars['line'][$this->p_vars['linecount']] = + new parserStringWithInlineTags; + } + if ($word == '}') + { + $this->p_vars['line'][$this->p_vars['linecount']]->add('{@'); + } else + { + $this->p_vars['line'][$this->p_vars['linecount']]->add('{@'.$word); + } + } elseif($this->p_flags['in_tag']) + { + if ($word == '}') + $this->p_vars['tag_value']->add('{@'.$word); + else + $this->p_vars['tag_value']->add('{@'.$word); + } + $this->p_vars['event_stack']->popEvent(); + $this->p_vars['inline_dockeyword_type'] = false; + $this->p_vars['inline_dockeyword_data'] = ''; + return; + } + } else + { + if ($word != "}") + { + $this->p_vars['inline_dockeyword_data'] .= $word; + } + } + if ($this->checkEventPop($word,$pevent)) + { + $this->wp->setWhiteSpace($this->p_vars['whitesp']); + if ($this->p_vars['inline_dockeyword_type']=='link') + { + // support hyperlinks of any protocol + if (is_numeric(strpos($this->p_vars['inline_dockeyword_data'],'://')) || (strpos(trim($this->p_vars['inline_dockeyword_data']),'mailto:') === 0)) + { + // if there is more than 1 parameter, the stuff after the space is the hyperlink text + if (strpos(trim($this->p_vars['inline_dockeyword_data']),' ')) + { + $i1 = strpos(trim($this->p_vars['inline_dockeyword_data']),' ') + 1; + $link = substr(trim($this->p_vars['inline_dockeyword_data']),0,$i1 - 1); + $text = substr(trim($this->p_vars['inline_dockeyword_data']),$i1); + $this->p_vars['inline_dockeyword_data'] = new parserLinkInlineTag($link,$text); +// ''.$text.''; + } + else + { + $this->p_vars['inline_dockeyword_data'] = new parserLinkInlineTag($this->p_vars['inline_dockeyword_data'],$this->p_vars['inline_dockeyword_data']); + } +// ''.$this->p_vars['inline_dockeyword_data'].''; + } else + { + if (!strpos($this->p_vars['inline_dockeyword_data'],',')) + { + $testp = explode('#',$this->p_vars['inline_dockeyword_data']); + if (count($testp) - 1) + $this->p_vars['inline_dockeyword_data'] = new parserLinkInlineTag($this->p_vars['inline_dockeyword_data'],$testp[1]); + else + $this->p_vars['inline_dockeyword_data'] = new parserLinkInlineTag($this->p_vars['inline_dockeyword_data'],$this->p_vars['inline_dockeyword_data']); + } else + $this->p_vars['inline_dockeyword_data'] = new parserLinkInlineTag($this->p_vars['inline_dockeyword_data'],$this->p_vars['inline_dockeyword_data']); + } + } + if ($this->p_vars['inline_dockeyword_type'] == 'tutorial') + { + $this->p_vars['inline_dockeyword_data'] = new parserTutorialInlineTag($this->p_vars['inline_dockeyword_data'],$this->p_vars['inline_dockeyword_data']); + } + if ($this->p_vars['inline_dockeyword_type'] == 'source') + { + $this->getSource(); + $this->p_vars['inline_dockeyword_data'] = new parserSourceInlineTag($this->p_vars['inline_dockeyword_data']); + } + if ($this->p_vars['inline_dockeyword_type'] == 'inheritdoc') + { + $this->p_vars['inline_dockeyword_data'] = new parserInheritdocInlineTag(); + } + if ($word == '*/') + { + if (!isset($this->p_vars['inline_dockeyword_type'])) $this->p_vars['inline_dockeyword_type'] = ''; + if (!isset($this->p_vars['tagname'])) $this->p_vars['tagname'] = ''; + if (!isset($this->p_vars['tag_value']) || !is_object($this->p_vars['tag_value'])) $this->p_vars['tag_value'] = new parserStringWithInlineTags; + addError(PDERROR_UNTERMINATED_INLINE_TAG,$this->p_vars['inline_dockeyword_type'],$this->p_vars['tagname'],'@'.$this->p_vars['tagname'].' '.$this->p_vars['tag_value']->getString()); + // when we add the error class, raise error here: we reached the end of the docblock + $this->wp->backupPos($word); + } + if ($this->p_flags['in_desc']) + { + $this->p_vars['line'][$this->p_vars['linecount']]->add($this->p_vars['inline_dockeyword_data']); + $this->p_vars['inline_dockeyword_type'] = false; + $this->p_vars['inline_dockeyword_data'] = ''; + } + elseif ($this->p_flags['in_tag']) + { + $this->p_vars['tag_value']->add($this->p_vars['inline_dockeyword_data']); + $this->p_vars['inline_dockeyword_type'] = false; + $this->p_vars['inline_dockeyword_data'] = ''; + } + } + } + + /** + * handler for INCLUDE. + * this handler recognizes include/require/include_once/include_once statements, and publishes the + * data to Render + */ + + function handleInclude($word, $pevent) + { + if (!$this->p_flags['in_include']) + { + $this->p_vars['linenum'] = $this->wp->linenum; + } + $this->p_flags['in_include'] = true; + $a = $this->checkEventPush( $word, $pevent); + if (!$this->p_flags['includename_isset']) + { + $this->p_flags['includename_isset'] = true; + $this->p_vars['include_name'] = $this->p_vars['last_word']; + if ($a) + $this->p_vars['include_value'] = ''; + else + $this->p_vars['include_value'] = $word; + unset($this->p_vars['quote_data']); + } else + { + if (!$a) + { + if (empty($this->p_vars['include_params_data'])) + { + if (isset($this->p_vars['quote_data'])) + { + $this->p_vars['include_value'] .= '"'.$this->p_vars['quote_data'].'"'; + unset($this->p_vars['quote_data']); + } + if ($word != ';') + $this->p_vars['include_value'] .= $word; + } + } else + { + $this->p_vars['include_params_data'] = ''; + } + } + + if ($this->checkEventPop($word,$pevent)) + { + $this->p_vars['include'] = new parserInclude; + $this->p_vars['include']->setLineNumber($this->p_vars['linenum']); + $this->p_flags['in_include'] = false; + $this->p_vars['include']->setName($this->p_vars['include_name']); + $this->p_vars['include']->setValue($this->p_vars['include_value']); + $this->publishEvent(PHPDOCUMENTOR_EVENT_INCLUDE,$this->p_vars['include']); + $this->p_flags['includename_isset'] = false; + unset($this->p_vars['include']); + unset($this->p_vars['include_name']); + unset($this->p_vars['include_value']); + unset($this->p_vars['include_params_data']); + } + } + + /** + * handler for INCLUDE_PARAMS. + * this handler parses the contents of ( ) in include/require/include_once/include_once statements + */ + + function handleIncludeParams($word, $pevent) + { + $this->checkEventPush( $word, $pevent); + + $this->p_flags['include_parens'] = true; + if(!isset($this->p_vars['include_params_data'])) $this->p_vars['include_params_data'] = ''; + + if ($this->checkEventPop($word,$pevent)) + { + if (isset($this->p_vars['quote_data'])) + { + $this->p_vars['include_value'] = $this->p_vars['include_params_data'].'"'.$this->p_vars['quote_data'].'"'; + unset($this->p_vars['quote_data']); + } else { + if (!empty($this->p_vars['include_params_data'])) + $this->p_vars['include_value'] = $this->p_vars['include_params_data']; + else + $this->p_vars['include_value'] = trim($this->p_vars['last_word']); + } + } + if (isset($this->p_vars['quote_data'])) + { + $this->p_vars['include_params_data'] .= '"'.$this->p_vars['quote_data'].'"'; + unset($this->p_vars['quote_data']); + } + if (($word != "'") && ($word != '"')) + $this->p_vars['include_params_data'] .= $word; + } + + /** + * handler for INCLUDE_PARAMS_PARENTHESIS. + * this handler takes all parenthetical statements within file in: + * include statement include(file), and handles them properly + */ + + function handleIncludeParamsParenthesis($word, $pevent) + { + if (isset($this->p_vars['quote_data'])) + { + $this->p_vars['include_params_data'] .= '"'.$this->p_vars['quote_data'].'"'; + unset($this->p_vars['quote_data']); + } + $this->p_vars['include_params_data'] .= $word; + $this->checkEventPush( $word, $pevent); + $this->checkEventPop( $word, $pevent); + } + /**#@-*/ + /** + * this function checks whether parameter $word is a token for pushing a new event onto the Event Stack. + * @return mixed returns false, or the event number + */ + + function checkEventPush($word,$pevent) + { + $e = false; + if (isset($this->pushEvent[$pevent])) + { + if (isset($this->pushEvent[$pevent][strtolower($word)])) + $e = $this->pushEvent[$pevent][strtolower($word)]; + } + if ($e) + { + $this->p_vars['event_stack']->pushEvent($e); + return $e; + } else { + return false; + } + } + + /** + * this function checks whether parameter $word is a token for popping the current event off of the Event Stack. + * @return mixed returns false, or the event number popped off of the stack + */ + + function checkEventPop($word,$pevent) + { + if (!isset($this->popEvent[$pevent])) return false; + if (in_array(strtolower($word),$this->popEvent[$pevent])) + { + return $this->p_vars['event_stack']->popEvent(); + } else { + return false; + } + } + + /** + * setup the parser tokens, and the pushEvent/popEvent arrays + * @see $tokens, $pushEvent, $popEvent + */ + + function setupStates() + { + $this->tokens[STATE_PHPCODE] = array(" ", "\t",";","?>","","/**#@+","/**#@-*/","/**", "//","/*","#","\r\n","\n","\r","(",'<<<','"',"'"); + $this->tokens[STATE_QUOTE] = array("\\\"","\\\\","\""); + $this->tokens[STATE_LOGICBLOCK] = array("{","}","\"","'","/*","//","#","?>","",'<<<','global','static'); + $this->tokens[STATE_FUNC_GLOBAL] = array("\"","'","/*","//","#",";",","); + $this->tokens[STATE_STATIC_VAR] = array("\"","'","/*","//","#",";",",",'=','array'); + $this->tokens[STATE_STATIC_VAR_VALUE] = array("/*","//","#"," ","\t",";","=","\"","'","array",","); + $this->tokens[STATE_NOEVENTS] = array("'); + $this->tokens[STATE_COMMENTBLOCK] = array("*/","\n"); + $this->tokens[STATE_COMMENT] = array("\r\n","\r","\n"); + $this->tokens[STATE_DEFINE] = array(" ","(",";"); + $this->tokens[STATE_DEFINE_PARAMS] = array("/*","//","#",",",")"," ","'","\"","("); + $this->tokens[STATE_DEFINE_PARAMS_PARENTHESIS] = array("(","'","\"",")"); + $this->tokens[STATE_FUNCTION_PARAMS] = array("/*","//","#","\"",",",")","="," ","'","("); + $this->tokens[STATE_SINGLEQUOTE] = array("'","\\'","\\\\"); + $this->tokens[STATE_CLASS] = array(" ", "\t", "?>", "", ";", "}", "{", + "/**#@+", "/**#@-*/", "/**", "//", "/*", "#", + "\r\n", "\n", "\r","("); + $this->tokens[STATE_DOCBLOCK] = array("*/","*","@","\r\n","\n","\r",". ",".\n",".\t",'{@'); + $this->tokens[STATE_DOCBLOCK_TEMPLATE] = array("*/","*","@","\r\n","\n","\r",". ",".\n",".\t",'{@'); + $this->tokens[STATE_DOCKEYWORD] = array("@","*/","*","\n","\r\n","\r","\t"," ","<",">",'{@'); + $this->tokens[STATE_INLINE_DOCKEYWORD] = array("{@","}","\t"," ","*/"); + $this->tokens[STATE_DOCKEYWORD_EMAIL] = array(">","\n","\r\n","\r"); + $this->tokens[STATE_VAR] = array("/*","//","#"," ","\t",";","=",",","\"","'","array"); + $this->tokens[STATE_GLOBAL] = array("/*","//","#"," ","\t",";","=","\"","'"); + $this->tokens[STATE_GLOBAL_VALUE] = array("/*","//","#"," ","\t",";","=","\"","'","array"); + $this->tokens[STATE_ARRAY] = array("/*","//","#","(",")","\"","'","array"); + $this->tokens[STATE_FUNCTION] = array("(","{","}"," ","\t","&","/*","//","#"); + $this->tokens[STATE_OUTPHP] = array("'); + $this->tokens[STATE_EOFQUOTE] = array(" ","\t","\n"); + $this->tokens[STATE_ESCAPE] = false;// this tells the word parser to just cycle + $this->tokens[STATE_INCLUDE] = array(" ","(",";","'",'"'); + $this->tokens[STATE_INCLUDE_PARAMS] = array("/*",")"," ","'","\"","("); + $this->tokens[STATE_INCLUDE_PARAMS_PARENTHESIS] = array("(","'","\"",")"); + + // For each event word to event mapings + $this->pushEvent[PARSER_EVENT_QUOTE] = + array( + "\\" => PARSER_EVENT_ESCAPE + ); + $this->popEvent[PARSER_EVENT_QUOTE] = array("\""); +########################## + + $this->pushEvent[PARSER_EVENT_LOGICBLOCK] = + array( + "\"" => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_SINGLEQUOTE, + "//" => PARSER_EVENT_COMMENT, + "#" => PARSER_EVENT_COMMENT, + "global" => PARSER_EVENT_FUNC_GLOBAL, + "static" => PARSER_EVENT_STATIC_VAR, + "/*" => PARSER_EVENT_COMMENTBLOCK, + "{" => PARSER_EVENT_LOGICBLOCK, + "?>" => PARSER_EVENT_OUTPHP, + "" => PARSER_EVENT_OUTPHP, + "<<<" => PARSER_EVENT_EOFQUOTE + ); + $this->popEvent[PARSER_EVENT_LOGICBLOCK] = array("}"); +########################## + + $this->pushEvent[PARSER_EVENT_FUNC_GLOBAL] = + array( + "\"" => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_SINGLEQUOTE, + "//" => PARSER_EVENT_COMMENT, + "#" => PARSER_EVENT_COMMENT, + "/*" => PARSER_EVENT_COMMENTBLOCK, + ); + $this->popEvent[PARSER_EVENT_FUNC_GLOBAL] = array(";"); +########################## + + $this->pushEvent[PARSER_EVENT_STATIC_VAR] = + array( + "\"" => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_SINGLEQUOTE, + "//" => PARSER_EVENT_COMMENT, + "#" => PARSER_EVENT_COMMENT, + "/*" => PARSER_EVENT_COMMENTBLOCK, + "=" => PARSER_EVENT_STATIC_VAR_VALUE, + ); + $this->popEvent[PARSER_EVENT_STATIC_VAR] = array(";"); +########################## + + $this->pushEvent[PARSER_EVENT_STATIC_VAR_VALUE] = + array( + "\"" => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_SINGLEQUOTE, + "array" => PARSER_EVENT_ARRAY, + "/*" => PARSER_EVENT_COMMENTBLOCK, + "//" => PARSER_EVENT_COMMENT, + "#" => PARSER_EVENT_COMMENT + ); + $this->popEvent[PARSER_EVENT_STATIC_VAR_VALUE] = array(";",","); +########################## + + $this->pushEvent[PARSER_EVENT_NOEVENTS] = + array( + " PARSER_EVENT_PHPCODE, + " PARSER_EVENT_PHPCODE, + '" => PARSER_EVENT_OUTPHP, + ); +########################## + + $this->pushEvent[PARSER_EVENT_FUNCTION] = + array( + "(" => PARSER_EVENT_FUNCTION_PARAMS, + "//" => PARSER_EVENT_COMMENT, + "#" => PARSER_EVENT_COMMENT, + "/*" => PARSER_EVENT_COMMENTBLOCK, + "{" => PARSER_EVENT_LOGICBLOCK + ); + $this->popEvent[PARSER_EVENT_FUNCTION] = array("}"); +########################## + + $this->pushEvent[PARSER_EVENT_DOCBLOCK] = + array( + "@" => PARSER_EVENT_DOCKEYWORD, + "{@" => PARSER_EVENT_INLINE_DOCKEYWORD + ); + $this->popEvent[PARSER_EVENT_DOCBLOCK] = array("*/"); +########################## + + $this->pushEvent[PARSER_EVENT_DOCBLOCK_TEMPLATE] = + array( + "@" => PARSER_EVENT_DOCKEYWORD, + "{@" => PARSER_EVENT_INLINE_DOCKEYWORD + ); + $this->popEvent[PARSER_EVENT_DOCBLOCK_TEMPLATE] = array("*/"); +########################## + + $this->pushEvent[PARSER_EVENT_CLASS] = + array( + "function" => PARSER_EVENT_FUNCTION, + "var" => PARSER_EVENT_VAR, + "/**" => PARSER_EVENT_DOCBLOCK, + "/**#@+" => PARSER_EVENT_DOCBLOCK_TEMPLATE, + "/**#@-*/" => PARSER_EVENT_END_DOCBLOCK_TEMPLATE, + "//" => PARSER_EVENT_COMMENT, + "/*" => PARSER_EVENT_COMMENTBLOCK, + "#" => PARSER_EVENT_COMMENT, + "?>" => PARSER_EVENT_OUTPHP, + "" => PARSER_EVENT_OUTPHP, + ); + $this->popEvent[PARSER_EVENT_CLASS] = array("}"); +########################## + + $this->pushEvent[PARSER_EVENT_DEFINE] = + array( + "/*" => PARSER_EVENT_COMMENTBLOCK, + "(" => PARSER_EVENT_DEFINE_PARAMS + ); + $this->popEvent[PARSER_EVENT_DEFINE] = array(";"); +########################## + + $this->pushEvent[PARSER_EVENT_INCLUDE] = + array( + "/*" => PARSER_EVENT_COMMENTBLOCK, + "(" => PARSER_EVENT_INCLUDE_PARAMS, + "'" => PARSER_EVENT_SINGLEQUOTE, + '"' => PARSER_EVENT_QUOTE, + ); + $this->popEvent[PARSER_EVENT_INCLUDE] = array(";"); +########################## + + $this->pushEvent[PARSER_EVENT_DEFINE_PARAMS] = + array( + "(" => PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS, + "'" => PARSER_EVENT_SINGLEQUOTE, + '"' => PARSER_EVENT_QUOTE, + "/*" => PARSER_EVENT_COMMENTBLOCK, + "//" => PARSER_EVENT_COMMENT, + "#" => PARSER_EVENT_COMMENT + ); + $this->popEvent[PARSER_EVENT_DEFINE_PARAMS] = array(")"); +########################## + + $this->pushEvent[PARSER_EVENT_INCLUDE_PARAMS] = + array( + "(" => PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS, + "'" => PARSER_EVENT_SINGLEQUOTE, + '"' => PARSER_EVENT_QUOTE, + ); + $this->popEvent[PARSER_EVENT_INCLUDE_PARAMS] = array(")"); +########################## + + $this->pushEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] = + array( + "(" => PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS, + "'" => PARSER_EVENT_SINGLEQUOTE, + '"' => PARSER_EVENT_QUOTE, + ); + $this->popEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] = array(")"); +########################## + + $this->pushEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] = + array( + "(" => PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS, + "'" => PARSER_EVENT_SINGLEQUOTE, + '"' => PARSER_EVENT_QUOTE, + ); + $this->popEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] = array(")"); +########################## + + $this->pushEvent[PARSER_EVENT_VAR] = + array( + "\"" => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_SINGLEQUOTE, + "array" => PARSER_EVENT_ARRAY, + "/*" => PARSER_EVENT_COMMENTBLOCK, + "//" => PARSER_EVENT_COMMENT, + "#" => PARSER_EVENT_COMMENT + ); + $this->popEvent[PARSER_EVENT_VAR] = array(";"); +########################## + + $this->pushEvent[PARSER_EVENT_DEFINE_GLOBAL] = + array( + "=" => PARSER_EVENT_GLOBAL_VALUE, + "\"" => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_SINGLEQUOTE, + "/*" => PARSER_EVENT_COMMENTBLOCK, + "//" => PARSER_EVENT_COMMENT, + "#" => PARSER_EVENT_COMMENT + ); + $this->popEvent[PARSER_EVENT_DEFINE_GLOBAL] = array(";"); +########################## + + $this->pushEvent[PARSER_EVENT_GLOBAL_VALUE] = + array( + "\"" => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_SINGLEQUOTE, + "array" => PARSER_EVENT_ARRAY, + "/*" => PARSER_EVENT_COMMENTBLOCK, + "//" => PARSER_EVENT_COMMENT, + "#" => PARSER_EVENT_COMMENT + ); + $this->popEvent[PARSER_EVENT_GLOBAL_VALUE] = array(";"); +########################## + + $this->pushEvent[PARSER_EVENT_COMMENT] = + array( + "\\" => PARSER_EVENT_ESCAPE + ); + $this->popEvent[PARSER_EVENT_COMMENT] = array("\n"); +########################## + + $this->popEvent[PARSER_EVENT_COMMENTBLOCK] = array("*/"); +########################## + $this->pushEvent[PARSER_EVENT_SINGLEQUOTE] = + array( + "\\" => PARSER_EVENT_ESCAPE + ); + + $this->popEvent[PARSER_EVENT_SINGLEQUOTE] = array("'"); +########################## + $this->pushEvent[PARSER_EVENT_FUNCTION_PARAMS] = + array( + "\"" => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_SINGLEQUOTE, + "array" => PARSER_EVENT_ARRAY, + "/*" => PARSER_EVENT_COMMENTBLOCK, + "//" => PARSER_EVENT_COMMENT, + "#" => PARSER_EVENT_COMMENT + ); + $this->popEvent[PARSER_EVENT_FUNCTION_PARAMS] = array(")"); +########################## + $this->pushEvent[PARSER_EVENT_DOCKEYWORD] = + array( +// "<" => PARSER_EVENT_DOCKEYWORD_EMAIL, + "{@" => PARSER_EVENT_INLINE_DOCKEYWORD, + ); + + $this->popEvent[PARSER_EVENT_DOCKEYWORD] = array("*/"); +########################## + + $this->popEvent[PARSER_EVENT_INLINE_DOCKEYWORD] = array("}","*/"); +########################## + + $this->popEvent[PARSER_EVENT_OUTPHP] = array("'); +########################## + + $this->popEvent[PARSER_EVENT_DOCKEYWORD_EMAIL] = array(">","\n"); + +########################## + $this->pushEvent[PARSER_EVENT_ARRAY] = + array( + "\"" => PARSER_EVENT_QUOTE, + "'" => PARSER_EVENT_SINGLEQUOTE, + "array" => PARSER_EVENT_ARRAY, + "/*" => PARSER_EVENT_COMMENTBLOCK, + "//" => PARSER_EVENT_COMMENT, + "#" => PARSER_EVENT_COMMENT + ); + $this->popEvent[PARSER_EVENT_ARRAY] = array(")"); +########################## + } + + /** + * tell the parser's WordParser {@link $wp} to set up tokens to parse words by. + * tokens are word separators. In English, a space or punctuation are examples of tokens. + * In PHP, a token can be a ;, a parenthesis, or even the word "function" + * @param $value integer an event number + * @see WordParser + */ + + function configWordParser($e) + { + $this->wp->setSeperator($this->tokens[($e + 100)]); + } + + /** + * Debugging function, takes an event number and attempts to return its name + * @param $value integer an event number + */ + + + function getParserEventName ($value) + { + $lookup = array( + PARSER_EVENT_NOEVENTS => "PARSER_EVENT_NOEVENTS", + PARSER_EVENT_PHPCODE => "PARSER_EVENT_PHPCODE", + PARSER_EVENT_DOCBLOCK => "PARSER_EVENT_DOCBLOCK", + PARSER_EVENT_FUNCTION => "PARSER_EVENT_FUNCTION", + PARSER_EVENT_CLASS => "PARSER_EVENT_CLASS", + PARSER_EVENT_DEFINE => "PARSER_EVENT_DEFINE", + PARSER_EVENT_DEFINE_PARAMS => "PARSER_EVENT_DEFINE_PARAMS", + PARSER_EVENT_COMMENT => "PARSER_EVENT_COMMENT", + PARSER_EVENT_COMMENTBLOCK => "PARSER_EVENT_COMMENTBLOCK", + PARSER_EVENT_ESCAPE => "PARSER_EVENT_ESCAPE", + PARSER_EVENT_QUOTE => "PARSER_EVENT_QUOTE", + PARSER_EVENT_FUNCTION_PARAMS => "PARSER_EVENT_FUNCTION_PARAMS", + PARSER_EVENT_SINGLEQUOTE => "PARSER_EVENT_SINGLEQUOTE", + PARSER_EVENT_VAR => "PARSER_EVENT_VAR", + PARSER_EVENT_LOGICBLOCK => "PARSER_EVENT_LOGICBLOCK", + PARSER_EVENT_OUTPHP => "PARSER_EVENT_OUTPHP", + PARSER_EVENT_DOCKEYWORD => "PARSER_EVENT_DOCKEYWORD", + PARSER_EVENT_DOCKEYWORD_EMAIL => "PARSER_EVENT_DOCKEYWORD_EMAIL", + PARSER_EVENT_ARRAY => "PARSER_EVENT_ARRAY", + PARSER_EVENT_INLINE_DOCKEYWORD => "PARSER_EVENT_INLINE_DOCKEYWORD", + PARSER_EVENT_EOFQUOTE => "PARSER_EVENT_EOFQUOTE", + PARSER_EVENT_INCLUDE => "PARSER_EVENT_INCLUDE", + PARSER_EVENT_INCLUDE_PARAMS => "PARSER_EVENT_INCLUDE_PARAMS", + PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS => "PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS", + PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS => "PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS", + PARSER_EVENT_DEFINE_GLOBAL => "PARSER_EVENT_DEFINE_GLOBAL", + PARSER_EVENT_GLOBAL_VALUE => "PARSER_EVENT_GLOBAL_VALUE", + PARSER_EVENT_FUNC_GLOBAL => "PARSER_EVENT_FUNC_GLOBAL", + PARSER_EVENT_STATIC_VAR => "PARSER_EVENT_STATIC_VAR", + PARSER_EVENT_DOCBLOCK_TEMPLATE => "PARSER_EVENT_DOCBLOCK_TEMPLATE", + PARSER_EVENT_END_DOCBLOCK_TEMPLATE => "PARSER_EVENT_END_DOCBLOCK_TEMPLATE", + PARSER_EVENT_METHOD_LOGICBLOCK => 'PARSER_EVENT_METHOD_LOGICBLOCK', + PARSER_EVENT_CLASS_MEMBER => 'PARSER_EVENT_CLASS_MEMBER', + PARSER_EVENT_METHOD => 'PARSER_EVENT_METHOD', + PARSER_EVENT_QUOTE_VAR => 'PARSER_EVENT_QUOTE_VAR', + PARSER_EVENT_ACCESS_MODIFIER => 'PARSER_EVENT_ACCESS_MODIFIER', + PARSER_EVENT_IMPLEMENTS => 'PARSER_EVENT_IMPLEMENTS', + PARSER_EVENT_CLASS_CONSTANT => 'PARSER_EVENT_CLASS_CONSTANT', + PARSER_EVENT_VAR_ARRAY => 'PARSER_EVENT_VAR_ARRAY', + PARSER_EVENT_VAR_ARRAY_COMMENT =>'PARSER_EVENT_VAR_ARRAY_COMMENT', + ); + if (isset($lookup[$value])) + return $lookup[$value]; + else return $value; + } +} + +/** + * Global package page parser + * + * @deprecated in favor of tutorials + * @tutorial tutorials.pkg + * @package phpDocumentor + * @subpackage Parsers + */ +class ppageParser extends Parser +{ + /** @var string */ + var $package = false; + /** @var string */ + var $subpackage = ''; + /** + * set up invariant Parser variables + */ + function ppageParser() + { + Parser::Parser(); + $this->allowableInlineTags = $GLOBALS['_phpDocumentor_inline_tutorial_tags_allowed']; + $this->eventHandlers = array(); + $this->eventHandlers[PARSER_EVENT_NOEVENTS] = 'defaultHandler'; + $this->eventHandlers[PARSER_EVENT_INLINE_DOCKEYWORD] = 'handleInlineDocKeyword'; + } + + /** + * set up invariant Parser variables + */ + function setupStates() + { + $this->tokens[STATE_NOEVENTS] = array("{@","}"); + $this->tokens[STATE_INLINE_DOCKEYWORD] = array("{@","}","\t"," "); + +########################## + + $this->pushEvent[PARSER_EVENT_NOEVENTS] = + array( + "{@" => PARSER_EVENT_INLINE_DOCKEYWORD + ); +########################## + + $this->popEvent[PARSER_EVENT_INLINE_DOCKEYWORD] = array("}"); + } + + /** + * Parse a new file + * + * @param string $parse_data + * @param string $package + * @param int $subpackage + * @return mixed false or parsed data + */ + function parse (&$parse_data,$xml,$package = 'default',$subpackage = '',$tutorial = '', + $category='default', $path='') + { + $this->setupStates(); + $this->p_vars['total'] = new parserPackagePage($package,$xml); + $this->p_vars['tutorial'] = $tutorial; + $this->_path = $path; + $this->category = $category; + $this->package = $package; + if (!isset($subpackage) || !$subpackage) $subpackage = ''; + $this->subpackage = $subpackage; + if (strlen($parse_data) == 0) + { + return false; + } + + // initialize variables so E_ALL error_reporting doesn't complain + $pevent = 0; + $word = 0; + $this->p_vars['event_stack'] = new EventStack; + // change this to a new ParserStringWithInlineTags, and change all $total .= blah to $total->add(blah) + // then modify phpDocumentor_IntermediateParser->Convert to convert all package pages (the package page handler in phpDocumentor_IntermediateParser should + // save them all in a variable) to perform the linking. then, remove the legacy code from handleDocBlock + // and handleClass in Render.inc, and do a loop that converts each package page, and passes it to handleEvent + // just like Converter::walk does with the other elements. The only other addition that might be good is a + // new descendant of parserElement parserPackagePage that contains the data and stuff. Hope this helps :) + $total = ''; + + $this->wp->setup($parse_data); + + $this->p_flags['reset_quote_data'] = true; + + do + { + $lpevent = $pevent; + $pevent = $this->p_vars['event_stack']->getEvent(); + if ($lpevent != $pevent) + { + $this->p_vars['last_pevent'] = $lpevent; + } + + if ($this->p_vars['last_pevent'] != $pevent) + { + // its a new event so the word parser needs to be reconfigured + $this->configWordParser($pevent); + } + + if (!$xml) + $this->publishEvent(PHPDOCUMENTOR_EVENT_NEWSTATE,($pevent + 100)); + + + $this->p_vars['last_word'] = $word; + $word = $this->wp->getWord(); + + if (0)//PHPDOCUMENTOR_DEBUG == true) + { + echo "LAST: |" . $this->p_vars['last_word'] . "|\n"; + echo "PEVENT: " . $this->getParserEventName($pevent) . "\n"; + echo $this->wp->getPos() . ": |$word|\n"; + } + if (isset($this->eventHandlers[$pevent])) + { + $handle = $this->eventHandlers[$pevent]; + $this->$handle($word, $pevent); + } + } while (!($word === false)); + if (!$xml) + $this->PublishEvent(PHPDOCUMENTOR_EVENT_PACKAGEPAGE,$this->p_vars['total']); + else + return $this->p_vars['total']->value; + } + + /** + * Handles all non-inline tags + * + * @param string token + * @param integer parser event + */ + function defaultHandler($word, $pevent) + { + if (!$this->checkEventPush( $word, $pevent)) + { + if ($word) $this->p_vars['total']->add($word); + } + } + + /** + * handler for INLINE_DOCKEYWORD. + * this handler recognizes {@inline tags} like link, and parses them, replacing them directly + * in the text flow with their output. + * @param string token + * @param integer parser event + */ + + function handleInlineDockeyword($word, $pevent) + { + // echo $this->wp->getPos() . ": |$word|\n"; + + // echo "docktype: $this->p_vars['inline_dockeyword_type']\n"; + if (!isset($this->p_vars['inline_dockeyword_type'])) $this->p_vars['inline_dockeyword_type'] = false; + if (!isset($this->p_vars['inline_dockeyword_data'])) $this->p_vars['inline_dockeyword_data'] = ''; + if (!$this->p_vars['inline_dockeyword_type']) + { + if (in_array($word,$this->allowableInlineTags)) + { + $this->p_vars['inline_dockeyword_type'] = strtolower($word); + $this->p_vars['whitesp'] = $this->wp->returnWhiteSpace; + $this->wp->setWhiteSpace(true); + } else { + if ($word == '}') + $this->p_vars['total']->add('{@'); + else + { + $this->p_vars['total']->add('{@'.$word); + $this->p_vars['event_stack']->popEvent(); + } + $this->p_vars['inline_dockeyword_type'] = false; + $this->p_vars['inline_dockeyword_data'] = ''; + } + } else + { + if ($word != "}") + { + $this->p_vars['inline_dockeyword_data'] .= $word; + } + } + if ($this->checkEventPop($word,$pevent)) + { + $this->wp->setWhiteSpace($this->p_vars['whitesp']); + if ($this->p_vars['inline_dockeyword_type']=='link') + { + // support hyperlinks of any protocol + if (is_numeric(strpos($this->p_vars['inline_dockeyword_data'],'://')) || (strpos(trim($this->p_vars['inline_dockeyword_data']),'mailto:') === 0)) + { + // if there is more than 1 parameter, the stuff after the space is the hyperlink text + if (strpos(trim($this->p_vars['inline_dockeyword_data']),' ')) + { + $i1 = strpos(trim($this->p_vars['inline_dockeyword_data']),' ') + 1; + $link = substr(trim($this->p_vars['inline_dockeyword_data']),0,$i1 - 1); + $text = substr(trim($this->p_vars['inline_dockeyword_data']),$i1); + $this->p_vars['inline_dockeyword_data'] = new parserLinkInlineTag($link,$text); +// ''.$text.''; + } + else + { + $this->p_vars['inline_dockeyword_data'] = new parserLinkInlineTag($this->p_vars['inline_dockeyword_data'],$this->p_vars['inline_dockeyword_data']); + } +// ''.$this->p_vars['inline_dockeyword_data'].''; + } else + { + $testp = explode('#',$this->p_vars['inline_dockeyword_data']); + if (count($testp) - 1) $this->p_vars['inline_dockeyword_data'] = $testp[1]; + $this->p_vars['inline_dockeyword_data'] = new parserLinkInlineTag($this->p_vars['inline_dockeyword_data'],$this->p_vars['inline_dockeyword_data']); + } + } + if ($this->p_vars['inline_dockeyword_type']=='id') + { + $this->p_vars['inline_dockeyword_data'] = new parserIdInlineTag($this->category,$this->package,$this->subpackage,$this->p_vars['tutorial'],trim($this->p_vars['inline_dockeyword_data'])); + } + if ($this->p_vars['inline_dockeyword_type'] == 'tutorial') + { + $this->p_vars['inline_dockeyword_data'] = new parserTutorialInlineTag($this->p_vars['inline_dockeyword_data'],$this->p_vars['inline_dockeyword_data']); + } + if ($this->p_vars['inline_dockeyword_type'] == 'toc') + { + $this->p_vars['inline_dockeyword_data'] = new parserTocInlineTag(); + } + if ($this->p_vars['inline_dockeyword_type'] == 'example') + { + $example = + new parserExampleInlineTag($this->p_vars['inline_dockeyword_data'], $this->_path, true); + $this->p_vars['total']->add($example->getProgramListing()); + } else + { + $this->p_vars['total']->add($this->p_vars['inline_dockeyword_data']); + } + $this->p_vars['inline_dockeyword_type'] = false; + $this->p_vars['inline_dockeyword_data'] = ''; + } + } +} +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/ParserData.inc b/buildscripts/PhpDocumentor/phpDocumentor/ParserData.inc new file mode 100644 index 00000000..d7d0f285 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/ParserData.inc @@ -0,0 +1,725 @@ + + * @since 1.0rc1 + * @version $Id: ParserData.inc,v 1.1 2005/10/17 18:36:57 jeichorn Exp $ + */ +/** + * Contains information about a PHP file, used to group procedural elements + * together. + * @package phpDocumentor + * @subpackage ParserData + * @author Greg Beaver + * @since 1.0rc1 + * @version $Id: ParserData.inc,v 1.1 2005/10/17 18:36:57 jeichorn Exp $ + */ +class parserPage +{ + /** + * Type is used by many functions to skip the hassle of if + * phpDocumentor_get_class($blah) == 'parserBlah' + * @var string + */ + var $type = 'page'; + /** + * not implemented in this version, will be used to link xml output pages + * @var string + */ + var $id = ''; + /** + * filename.ext (no path) + * @var string + */ + var $file = ''; + /** + * relative source location + * @var string + */ + var $sourceLocation = ''; + /** + * phpdoc-safe name (only letters, numbers and _) + * @var string + */ + var $name = ''; + /** + * @var string + */ + var $category = 'default'; + /** + * @var string + */ + var $package = 'default'; + /** + * @var string + */ + var $subpackage = ''; + /** + * @var string + */ + var $parserVersion = PHPDOCUMENTOR_VER; + /** + * not implemented yet + * file modification date, will be used for makefiles + * @var string + */ + var $modDate = ''; + /** + * @var string full path this page represents + */ + var $path = ''; + /** + * Tokenized source code of the file + * @var array + */ + var $source = array(); + /** + * Used to limit output, contains contents of --packageoutput commandline. + * Does not increase parsing time. Use --ignore for that + * @see phpDocumentor_IntermediateParser::$packageoutput, Converter::$package_output + * @var mixed either false or an array of packages + */ + var $packageOutput = false; + + /** + * sets package to default package + * @global string default package name + */ + function parserPage() + { + global $phpDocumentor_DefaultPackageName; + $this->package = $GLOBALS['phpDocumentor_DefaultPackageName']; + } + + /** + * @return string always "page" + */ + function getType() + { + return 'page'; + } + + /** + * Sets the source code of the file for highlighting. + * + * PHP 4.3.0+ passes an array of tokenizer tokens by line number. PHP + * 4.2.3- passes a string to be passed to {@link highlight_string()} + * @param string|array + */ + function setSource($source) + { + $this->source = $source; + } + + /** + * Sets the name to display in documentation (can be an alias set with @name) + * @param string $file + */ + function setFile($file) + { + $this->file = $file; + } + + /** + * @return string filename.ext or @name alias + */ + function getFile() + { + if (!isset($this->file)) return false; + return $this->file; + } + + /** + * @param string $path full path to file + */ + function setPath($path) + { + // look for special windows case + if(SMART_PATH_DELIMITER === '\\') + $this->path = strtr($path,'/','\\'); + else + $this->path = $path; + } + + /** + * @return string fully delimited path (OS-dependent format) + */ + function getPath() + { + if (!isset($this->path)) return false; + return $this->path; + } + + /** + * @param array $packages array of packages to display in documentation (package1,package2,...) + * @see phpDocumentor_IntermediateParser::$packageoutput + */ + function setPackageOutput($packages) + { + $this->packageOutput = $packages; + } + + /** + * @return array array of packages (package1,package2,...) + * @see phpDocumentor_IntermediateParser::$packageoutput + */ + function getPackageOutput() + { + return $this->packageOutput; + } + + /** + * @param string $name phpdoc-safe name (only _, numbers and letters) set by Parser::parse() + * @see Parser::parse() + */ + function setName($name) + { + $this->name = $name; + } + + /** + * @return string phpdoc-safe name (only _, numbers and letters) + */ + function getName() + { + if (!isset($this->name)) return false; + return $this->name; + } + + /** + * @param string $source path of this file relative to program root + */ + function setSourceLocation($source) + { + $this->sourceLocation = $source; + } + + /** + * @param Converter + * @param boolean if this parameter is true, it will truncate the source location to the + * subdirectory of pear + * @return string path of this file relative to program root + */ + function getSourceLocation ($c,$pearize = false) + { + global $_phpDocumentor_options; + if (!isset($this->sourceLocation)) return false; + if ($pearize) + { + $sl = $this->sourceLocation; + if (strpos($sl,'pear/')) + { + $sl = substr($sl,strpos($sl,'pear/') + 5); + return $sl; + } else + { + return str_replace($_phpDocumentor_options['Program_Root'] . PATH_DELIMITER,'',$sl); + } + return $sl; + } + return $this->sourceLocation; + } + /** + * Not implemented in this version + * @return boolean tell the parser whether to parse the file, otherwise + * this function will retrieve the parsed data from external file + */ + function getParseData() + { + return true; + } +} + +/** + * Contains an in-memory representation of all documentable elements + * ({@link parserPage}, {@link parserFunction}, {@link parserDefine}, + * {@link parserInclude}, {@link parserClass}, {@link parserMethod}, + * {@link parserVar}) and their DocBlocks ({@link parserDocBlock}). + * + * This class works in coordination with {@link phpDocumentor_IntermediateParser} + * to take output from {@link Parser::handleEvent()} and create indexes, links, + * and other assorted things (all documented in phpDocumentor_IntermediateParser + * and {@link Converter}) + * @package phpDocumentor + * @subpackage ParserData + * @author Greg Beaver + * @since 1.0rc1 + * @version $Id: ParserData.inc,v 1.1 2005/10/17 18:36:57 jeichorn Exp $ + */ +class parserData +{ + /** + * {@link parserPage} element that is this parserData's parent, or false if + * not set. + * @var false|parserPage + */ + var $parent = false; + /** + * array of parsed elements + * @var array + */ + var $elements = array(); + /** + * array of parsed elements with @access private + * @var array + */ + var $privateelements = array(); + /** + * array of parsed class elements + * @var array + */ + var $classelements = array(); + + /** + * @var parserTutorial|false + */ + var $tutorial = false; + /** + * array of parsed class elements with @access private + * @var array + */ + var $privateclasselements = array(); + /** + * array of links descended from {@link abstractLink} + * @var array + * @see pageLink, defineLink, classLink, functionLink, methodLink, varLink + */ + var $links = array(); + /** + * used by {@link phpDocumentor_IntermediateParser::handleDocBlock()} to + * determine whether a docblock is a page-level docblock or not. $clean is + * true as long as only 0 or 1 docblock has been parsed, and no element + * other than parserPage has been parsed + * @var boolean + */ + var $clean = true; + /** + * DocBlock ({@link parserDocBlock}) for this page, or false if not set + * @var mixed + */ + var $docblock = false; + /** + * Flag used to determine whether a page-level docblock is present + * @var boolean + * @access private + */ + var $_explicitdocblock = false; + /** + * Type is used by many functions to skip the hassle of if + * phpDocumentor_get_class($blah) == 'parserBlah' + * always 'page', used in element indexing and conversion functions found in + * {@link Converter} + * @var string + */ + var $type = 'page'; + + /** + * @param parserElement add a parsed element to the {@link $elements} array, + * also sets {@link $clean} to false + */ + function addElement(&$element) + { + $element->setPath($this->parent->path); + if ($element->getType() == 'class' || $element->getType() == 'method' || $element->getType() == 'var' + || $element->getType() == 'const') + { + $this->classelements[] = $element; + } else + { + $this->elements[] = $element; + } + $this->clean = false; + } + + /** + * @param parserTutorial + * @param Converter + */ + function addTutorial($t,&$c) + { + $this->tutorial = new tutorialLink; + $this->tutorial->addLink('',$t->path,$t->name,$t->package,$t->subpackage,$t->getTitle($c)); + } + + /** + * If this file has a tutorial associated with it, returns a link to the + * tutorial. + * @return tutorialLink + */ + function getTutorial() + { + return $this->tutorial; + } + + /** + * If the page-level DocBlock was present in the source, returns true + * @return boolean + */ + function hasExplicitDocBlock() + { + return $this->_explicitdocblock; + } + + /** + * Tells this page that its DocBlock was not implicit + */ + function explicitDocBlock() + { + $this->_explicitdocblock = true; + } + + /** + * @param parserElement element to add a new link (descended from + * {@link abstractLink})to the {@link $links} array + * @param string classname for elements that are class-based (this may be + * deprecated in the future, as the classname should be + * contained within the element. if $element is a page, this + * parameter is a package name + * @param string subpackage name for page elements + */ + function addLink(&$element,$classorpackage = '', $subpackage = '') + { + switch($element->type) + { + case 'function': + $x = new functionLink; + $x->addLink($this->parent->path, $this->parent->name, $element->name, $element->docblock->package, $element->docblock->subpackage); + return $x; + break; + case 'define': + $x = new defineLink; + $x->addLink($this->parent->path, $this->parent->name, $element->name, $element->docblock->package, $element->docblock->subpackage); + return $x; + break; + case 'global': + $x = new globalLink; + $x->addLink($this->parent->path, $this->parent->name, $element->name, $element->docblock->package, $element->docblock->subpackage); + return $x; + break; + case 'class': + $x = new classLink; + $x->addLink($this->parent->path, $this->parent->name, $element->name, $element->docblock->package, $element->docblock->subpackage); + return $x; + break; + case 'method': + $x = new methodLink; + $x->addLink($classorpackage, $this->parent->path, $this->parent->name, $element->name, $element->docblock->package, $element->docblock->subpackage); + return $x; + break; + case 'var': + $x = new varLink; + $x->addLink($classorpackage, $this->parent->path, $this->parent->name, $element->name, $element->docblock->package, $element->docblock->subpackage); + return $x; + break; + case 'page': + if (empty($classorpackage)) $classorpackage = $GLOBALS['phpDocumentor_DefaultPackageName']; + $x = new pageLink; + $x->addLink($element->path,$element->name,$element->file,$classorpackage, $subpackage); + return $x; + break; + } + } + + function &getLink(&$c, $text = false) + { + return $c->getPageLink($this->parent->file, $this->docblock->package, $this->parent->path, $text); + } + + /** + * returns a list of all classes declared in a file + * @param Converter &$c + * @return array Format: array(packagename => parserClass,packagename => parserClass,...) + */ + function getClasses(&$c) + { + $r = $c->classes->getClassesInPath($this->parent->path); + $rr = array(); + if ($r) + foreach($r as $class => $obj) + { + $rr[$obj->docblock->package][] = $obj; + } + return $rr; + } + + /** + * Get the output-safe filename (. changed to _) + * @return string + */ + function getName() + { + if (isset($this->parent) && $this->parent) + return $this->parent->getName(); + } + + /** + * @param parserPage parent element of this parsed data + */ + function setParent(&$parent) + { + $this->parent = $parent; + } + + /** + * @return bool returns the value of {@link $clean} + */ + function isClean() + { + return $this->clean; + } + + /** + * @param parserDocBlock + * @see parserDocBlock + */ + function setDocBlock(&$docblock) + { + $this->docblock = $docblock; + } +} + +/** + * Base class for all elements + * @package phpDocumentor + * @subpackage ParserData + * @abstract + * @author Greg Beaver + * @since 1.0rc1 + * @version $Id: ParserData.inc,v 1.1 2005/10/17 18:36:57 jeichorn Exp $ + */ +class parserBase +{ + /** + * Type is used by many functions to skip the hassle of if phpDocumentor_get_class($blah) == 'parserBlah' + * always base + * @var string + */ + var $type = 'base'; + /** + * set to different things by its descendants + * @abstract + * @var mixed + */ + var $value = false; + + /** + * @return string returns value of {@link $type} + */ + function getType() + { + return $this->type; + } + + /** + * @param mixed set the value of this element + */ + function setValue($value) + { + $this->value = $value; + } + + /** + * @return mixed get the value of this element (element-dependent) + */ + function getValue() + { + return $this->value; + } +} + + +/** + * Used to represent strings that contain inline tags, so that they can be properly parsed at link time + * @package phpDocumentor + * @subpackage ParserData + * @author Greg Beaver + * @since 1.0rc1 + * @version $Id: ParserData.inc,v 1.1 2005/10/17 18:36:57 jeichorn Exp $ + */ +class parserStringWithInlineTags extends parserBase +{ + /** + * Type is used by many functions to skip the hassle of if phpDocumentor_get_class($blah) == 'parserBlah' + * always '_string' + * @var string + */ + var $type = '_string'; + /** @access private */ + var $cache = false; + /** + * array of strings and {@link parserInlineTag}s + * Format: + * array(string1,string2,parserInlineTag1,string3,parserInlineTag2,...) + * @var array + */ + var $value = array(); + + /** + * equivalent to the . operator ($a = $b . $c) + * @param mixed either a string or a {@link parserInlineTag} + */ + function add($stringOrInlineTag) + { + if (is_string($stringOrInlineTag)) + { + if (!count($this->value)) + { + $this->value[] = $stringOrInlineTag; + return; + } + if (is_string($this->value[count($this->value) - 1])) + { + $this->value[count($this->value) - 1] .= $stringOrInlineTag; + return; + } else + { + $this->value[] = $stringOrInlineTag; + return; + } + } else + { + if (is_a($stringOrInlineTag,'parserinlinetag') && phpDocumentor_setup::checkIgnoreTag($stringOrInlineTag->inlinetype, true)) return; + $this->value[] = $stringOrInlineTag; + } + } + + /** + * Determine whether the string contains any inline tags + * @tutorial inlinetags.pkg + * @return boolean + */ + function hasInlineTag() + { + for($i=0;$ivalue);$i++) + { + if (is_a($this->value[$i],'parserinlinetag')) return true; + } + return false; + } + + /** + * Pass source code to any {@}source} tags contained within the string + * for later conversion. + * @param string|array source code ready to be highlighted + */ + function setSource($source) + { + for($i=0;$ivalue);$i++) + { + if (phpDocumentor_get_class($this->value[$i]) == 'parsersourceinlinetag') + { + $this->value[$i]->setSource($source); + } + } + } + + /** + * equivalent to trim(strlen($string)) + * @return integer length of the string this object represents + */ + function trimmedStrlen() + { + $a = 0; + for($i=0;$ivalue);$i++) + { + if (is_string($this->value[$i])) + { + if ($i == 0) + { + $a += strlen(ltrim($this->value[$i])); + } elseif ($i == count($this->value[$i]) - 1) + { + $a += strlen(chop($this->value[$i])); + } + } else + { + $a += $this->value[$i]->Strlen(); + } + } + return $a; + } + + /** + * return the string unconverted (all inline tags are taken out - this + * should only be used in pre-parsing to see if any other text + * is in the string) + * @uses parserInlineTag::getString() removes inline tag length, as it is + * indeterminate until conversion. + * @return string trimmed value + */ + function getString($trim = true) + { + $a = ''; + for($i=0; $ivalue); $i++) + { + if (is_string($this->value[$i])) + { + $a .= $this->value[$i]; + } else + { + $a .= $this->value[$i]->getString(); + } + } + if ($trim) $a = trim($a); + return $a; + } + + /** + * Use to convert the string to a real string with all inline tags parsed and linked + * @see Converter::returnSee() + * @param Converter + * @param boolean true if one needs to postprocess + * @param boolean false if the output should not be trimmed + */ + function Convert(&$converter,$postprocess = true, $trim = true) + { + if ($this->cache) + { + if ($converter->name == $this->cache['name'] && $converter->outputformat == $this->cache['output'] && $converter->checkState($this->cache['state']) && $this->cache['postprocess'] === $postprocess) return $this->cache['contents']; + if ($converter->name != $this->cache['name']) { + $this->cache = false; + } + } + if (is_string($this->value)) return $this->value; + $a = ''; + for($i=0; $ivalue); $i++) + { + if (is_string($this->value[$i])) + { + if ($postprocess && !method_exists($converter,'postProcess')) var_dump('a',$converter); + if ($postprocess) $a .= $converter->postProcess($this->value[$i]); + else $a .= $this->value[$i]; + } else + { + $a .= $this->value[$i]->Convert($converter, $postprocess); + } + } + if ($trim) { + $a = trim($a); + } + $this->cache = array('name' => $converter->name,'output' => $converter->outputformat, 'contents' => $a, 'state' => $converter->getState(), 'postprocess' => $postprocess); + return $a; + } +} + +?> \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/ParserDescCleanup.inc b/buildscripts/PhpDocumentor/phpDocumentor/ParserDescCleanup.inc new file mode 100644 index 00000000..bd80d104 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/ParserDescCleanup.inc @@ -0,0 +1,1456 @@ + + * @since 1.2 + */ +/**#@+ + * {@link parserDescParser} token constants + */ +/** when <> is found in a desc */ +define('PHPDOCUMENTOR_PDP_EVENT_CODE', 600); +/** when <> is found in a desc */ +define('PHPDOCUMENTOR_PDP_STATE_CODE', 700); +/** when <

            > is found in a desc */ +define('PHPDOCUMENTOR_PDP_EVENT_P', 601); +/** when <

            > is found in a desc */ +define('PHPDOCUMENTOR_PDP_STATE_P', 701); +/** when \n\n is found in a desc */ +define('PHPDOCUMENTOR_PDP_EVENT_DOUBLECR', 602); +/** when \n\n is found in a desc */ +define('PHPDOCUMENTOR_PDP_STATE_DOUBLECR', 702); +/** when <

            > is found in a desc */
            +define('PHPDOCUMENTOR_PDP_EVENT_PRE', 603);
            +/** when <
            > is found in a desc */
            +define('PHPDOCUMENTOR_PDP_STATE_PRE', 703);
            +/** when <
              >/<
                > is found in a desc */ +define('PHPDOCUMENTOR_PDP_EVENT_LIST', 604); +/** when <
                  >/<
                    > is found in a desc */ +define('PHPDOCUMENTOR_PDP_STATE_LIST', 704); +/** when <> is found in a desc */ +define('PHPDOCUMENTOR_PDP_EVENT_B', 605); +/** when <> is found in a desc */ +define('PHPDOCUMENTOR_PDP_STATE_B', 705); +/** when <> is found in a desc */ +define('PHPDOCUMENTOR_PDP_EVENT_I', 606); +/** when <> is found in a desc */ +define('PHPDOCUMENTOR_PDP_STATE_I', 706); +/** when <
                    > is found in a desc */ +define('PHPDOCUMENTOR_PDP_EVENT_BR', 607); +/** when <
                    > is found in a desc */ +define('PHPDOCUMENTOR_PDP_STATE_BR', 707); +/** when the << potential escape for tags is found in a desc */ +define('PHPDOCUMENTOR_PDP_EVENT_ESCAPE',608); +/** when the << potential escape for tags is found in a desc */ +define('PHPDOCUMENTOR_PDP_STATE_ESCAPE',708); +/** when << /pre>> is found in a <
                    ><
                    > section */ +define('PHPDOCUMENTOR_PDP_EVENT_ESCAPE_PRE',609); +/** when << /pre>> is found in a <
                    ><
                    > section */ +define('PHPDOCUMENTOR_PDP_STATE_ESCAPE_PRE',709); +/** when << /code>> is found in a <><> section */ +define('PHPDOCUMENTOR_PDP_EVENT_ESCAPE_CODE',610); +/** when << /code>> is found in a <><> section */ +define('PHPDOCUMENTOR_PDP_STATE_ESCAPE_CODE',710); +/** when <> is found in a desc */ +define('PHPDOCUMENTOR_PDP_EVENT_VAR',611); +/** when <> is found in a desc */ +define('PHPDOCUMENTOR_PDP_STATE_VAR',711); +/** when <> is found in a desc */ +define('PHPDOCUMENTOR_PDP_EVENT_SAMP',612); +/** when <> is found in a desc */ +define('PHPDOCUMENTOR_PDP_STATE_SAMP',712); +/** when <> is found in a desc */ +define('PHPDOCUMENTOR_PDP_EVENT_KBD',613); +/** when <> is found in a desc */ +define('PHPDOCUMENTOR_PDP_STATE_KBD',713); +/** when a simple list is found in a desc + * + * like + *
                    + *  o item 1
                    + *  o item 2
                    + * 
                    + */ +define('PHPDOCUMENTOR_PDP_EVENT_SIMLIST',614); +/** when a simple list is found in a desc + * + * like + *
                    + *  o item 1
                    + *  o item 2
                    + * 
                    + */ +define('PHPDOCUMENTOR_PDP_STATE_SIMLIST',714); +/**#@-*/ +/** +* Like WordParser but designed to handle an array with strings and +* {@link parserInlineTag}s +* @package phpDocumentor +* @subpackage WordParsers +* @author Greg Beaver +* @since 1.2 +*/ +class ObjectWordParser extends WordParser +{ + /** + * Determines whether text searching is case-sensitive or not + * @access private + */ + var $_casesensitive = false; + + function ObjectWordParser($casesensitive = false) + { + $this->_casesensitive = $casesensitive; + } + + /** + * Set the word parser to go. + * + * @param array {@link parserStringWithInlineTags::$value} style-array, with + * alternating text and inline tags + */ + function setup(&$input) + { +// if (is_string($input[0])) $input[0] = ltrim($input[0]); + $this->data = & $input; + $this->pos = 0; + $this->linenum = 0; + $this->linenumpos = 0; + $this->cache = array(); + reset($this->data); + list($this->index,) = each($this->data); + if (!is_object($this->data[$this->index])) + $this->size = strlen($this->data[$this->index]); + else $this->size = 0; + //$this->run = 0; + //$this->word = WORD_PARSER_RET_WORD; + } + + function getWord() + { + if (!isset($this->data[$this->index])) return false; + // return any inline tags unchanged + if (is_object($this->data[$this->index])) + { + $index = $this->index; + list($this->index,) = each($this->data); + $this->pos = 0; + if ($this->index) + { + if (!is_object($this->data[$this->index])) + $this->size = strlen($this->data[$this->index]); + else $this->size = 0; + $this->cache = array(); + return $this->data[$index]; + } else + { + return false; + } + } + //$st = $this->mtime(); + if ($this->size == $this->pos) + { + // cycle to next line in the array + list($this->index,) = each($this->data); + if (!$this->index) return false; + $this->pos = 0; + if (!is_object($this->data[$this->index])) + $this->size = strlen($this->data[$this->index]); + else $this->size = 0; + $this->cache = array(); + return $this->getWord(); + } + + $npos = $this->size; + if (is_array($this->wordseperators)) + { + //$this->wordseperators = array(); + foreach($this->wordseperators as $sep) + { + if (isset($this->cache[$sep])) + $tpos = $this->cache[$sep]; + else + $tpos = false; + if ($tpos < $this->pos || !is_int($tpos)) + { + if ($this->_casesensitive) + $tpos = strpos($this->data[$this->index],$sep,$this->pos); + else + $tpos = strpos(strtolower($this->data[$this->index]),$sep,$this->pos); + } + + if ( ($tpos < $npos) && !($tpos === false)) + { + //echo trim($sep) . "=$tpos\n"; + $npos = $tpos; + $seplen = strlen($sep); + } + else if (!($tpos === false)) + { + $this->cache[$sep] = $tpos; + } + } + } else { + // its time to cycle + return ""; + } + + $len = $npos - $this->pos; + if ($len == 0) + { + $len = $seplen; + } + + //$st3 = $this->mtime(); + $word = substr($this->data[$this->index],$this->pos,$len); + + // Change random other os newlines to the unix one + if ($word == "\r" || $word == "\r\n") + { + $word = "\n"; + } + + if ($this->linenumpos <= $this->pos) + { + $this->linenumpos = $this->pos + $len; + $this->linenum += count(explode("\n",$word)) - 1; + } + + if ($this->getsource) + { + $this->source .= $word; + } + $this->pos = $this->pos + $len; + //$this->word = WORD_PARSER_RET_SEP; + + // Things like // commenats rely on the newline to find their end so im going to have to return them + // never return worthless white space /t ' ' + if ($this->returnWhiteSpace == false) + { + if (strlen(trim($word)) == 0 && $word != "\n") + { + $word = $this->getWord(); + } + } + //$this->time3 = $this->time3 + ($this->mtime() - $st3); + //$this->time = $this->time + ($this->mtime() - $st); + return $word; + } + + /** + * Determine if the next word is an inline tag + * @return boolean + */ + function nextIsObjectOrNonNL() + { + return (($this->size == $this->pos) && isset($this->data[$this->index + 1]) + && is_object($this->data[$this->index + 1])) || + (($this->size > $this->pos) && !in_array($this->data[$this->index]{$this->pos}, array("\n", "\r"))); + } +} + +/** + * Parses a DocBlock description to retrieve abstract representations of + * <
                    >,<>,<

                    >,<

                      >,<
                        >,<
                      1. >,<>,<> + * @tutorial phpDocumentor.howto.pkg#basics.desc + * @package phpDocumentor + * @subpackage Parsers + * @author Greg Beaver + * @since 1.2 + */ +class parserDescParser extends Parser +{ + /**#@+ + * @access private + */ + /** + * @var array + */ + var $eventHandlers = array(PHPDOCUMENTOR_PDP_EVENT_CODE => 'handleCode', + PHPDOCUMENTOR_PDP_EVENT_PRE => 'handlePre', + PHPDOCUMENTOR_PDP_EVENT_P => 'handleP', + PHPDOCUMENTOR_PDP_EVENT_DOUBLECR => 'handleDoubleCR', + PHPDOCUMENTOR_PDP_EVENT_LIST => 'handleList', + PHPDOCUMENTOR_PDP_EVENT_B => 'handleB', + PHPDOCUMENTOR_PDP_EVENT_I => 'handleI', + PHPDOCUMENTOR_PDP_EVENT_VAR => 'handleVar', + PHPDOCUMENTOR_PDP_EVENT_KBD => 'handleKbd', + PHPDOCUMENTOR_PDP_EVENT_SAMP => 'handleSamp', + PHPDOCUMENTOR_PDP_EVENT_BR => 'handleBr', + PHPDOCUMENTOR_PDP_EVENT_ESCAPE => 'handleEscape', + PHPDOCUMENTOR_PDP_EVENT_ESCAPE_CODE => 'handleEscapeCode', + PHPDOCUMENTOR_PDP_EVENT_ESCAPE_PRE => 'handleEscapePre', + PHPDOCUMENTOR_PDP_EVENT_SIMLIST => 'handleSimpleList', + PARSER_EVENT_NOEVENTS => 'defaultHandler', + ); + + /** + * @var array + */ + var $pars = array(); + /** + * Determines whether parsing of <p> tags will occur, or double CR will + * be used + * @var boolean + */ + var $parse_Ps; + /** + * Context stack. + * + * Values can be 'normal', or any tag container like 'my_i', 'my_b'. This + * is used to determine which tag text or nested tags should be added to + * @var array + */ + var $_context = array('normal'); + /**#@-*/ + + /** + * sets $wp to be a {@link ObjectWordParser} + * + * $wp is the word parser that retrieves tokens + */ + function parserDescParser() + { + $this->wp = new ObjectWordParser; + } + + /** + * Parse a long or short description for tags + * + * @param array array of strings or {@link parserInlineTag}s + * @param boolean true if the description is a short description. (only 1 paragraph allowed in short desc) + * @param string name of the class to instantiate for each paragraph. parserDesc for desc/sdesc, + * parserStringWithInlineTags for tag data + * @staticvar integer used for recursion limiting if a handler for an event is not found + */ + function parse (&$parse_data,$sdesc = false,$ind_type = 'parserDesc') + { + static $endrecur = 0; + global $_phpDocumentor_setting; + if (!is_array($parse_data) || count($parse_data) == 0) + { + return false; + } + $this->p_vars['indtype'] = $ind_type; + $this->setupStates($sdesc); + if (isset($_phpDocumentor_setting['javadocdesc']) && $_phpDocumentor_setting['javadocdesc'] == 'on') + $this->parse_Ps = true; + + // initialize variables so E_ALL error_reporting doesn't complain + $pevent = 0; + $word = 0; + $this->p_vars['curpar'] = 0; + $this->pars = array(); + $this->p_vars['start'] = true; + $this->p_vars['event_stack'] = new EventStack; + + $this->wp->setup($parse_data,$sdesc); + $this->wp->setWhitespace(true); + $this->p_vars['list_count'] = 0; + if ($sdesc) $this->p_vars['start'] = false; + do + { + if (!isset($this->pars[$this->p_vars['curpar']])) $this->pars[$this->p_vars['curpar']] = new $ind_type; + $lpevent = $pevent; + $pevent = $this->p_vars['event_stack']->getEvent(); + if ($lpevent != $pevent) + { + $this->p_vars['last_pevent'] = $lpevent; + } + + if ($this->p_vars['last_pevent'] != $pevent) + { + // its a new event so the word parser needs to be reconfigured + $this->configWordParser($pevent); + } + + + $this->p_vars['last_word'] = $word; + $word = $this->wp->getWord(); + + if (0)//PHPDOCUMENTOR_DEBUG == true) + { + echo "----------------\n"; + echo "LAST: |" . htmlentities($this->p_vars['last_word']) . "|\n"; +// echo "INDEX: ".$this->p_vars['curpar']."\n"; + echo "PEVENT: " . $this->getParserEventName($pevent) . "\n"; + echo "LASTPEVENT: " . $this->getParserEventName($this->p_vars['last_pevent']) . "\n"; + echo $this->wp->getPos() . " WORD: |".htmlentities($word)."|\n\n"; + var_dump($this->_context); + } + if (isset($this->eventHandlers[$pevent])) + { + $handle = $this->eventHandlers[$pevent]; + if ($word !== false) $this->$handle($word, $pevent); + else + { + if (!count($this->pars[$this->p_vars['curpar']]->value)) unset($this->pars[$this->p_vars['curpar']]); + } + } else + { + debug('WARNING: possible error, no ParserDescParser handler for event number '.$pevent); + if ($endrecur++ == 25) + { + die("FATAL ERROR, recursion limit reached"); + } + } + if (is_object($word) || trim($word) != '') + { + $this->p_vars['start'] = false; + } + } while (is_object($word) || !($word === false) && $word != ''); + $context = $this->getContext(); + if ($context != 'normal') + { + if ($context == 'list' && $this->p_flags['simplelist']) + { + $this->p_vars['lists'][0]->addItem($this->p_vars['list_item'][0]); + unset($this->p_vars['list_item'][0]); + $this->setContext('normal'); + $this->addText($this->p_vars['lists'][0]); + } else addError(PDERROR_UNCLOSED_TAG,str_replace('my_','',$context)); + } + if ($this->p_vars['list_count'] > 0) addError(PDERROR_UNMATCHED_LIST_TAG); + if ($sdesc) + $this->publishEvent(2,$this->pars); + else + $this->publishEvent(1,$this->pars); + } + /**#@+ @access private */ + /** + * basic handling + * + * This function checks to see if the first thing in + * a description is the

                        tag. If so, it will switch + * into a mode of parsing out paragraphs by

                        instead + * of a double line-break + * + * It also removes extra whitespace + * @uses doSimpleList() + */ + function defaultHandler($word, $pevent) + { + $context = $this->getContext(); + if ($context != 'normal') $this->setContext('normal'); + if ($this->p_vars['start'] && is_string($word) && strtolower($word) == '

                        ') + { + $this->parse_Ps = true; + } + if (is_string($word) && $this->checkEventPush($word, $pevent)) return; +// if (!isset($this->parse_Ps) || !$this->parse_Ps) + { + if (!is_object($word) && ($word == ' ' && $this->p_vars['last_word'] == ' ')) return; + if ($pevent == PARSER_EVENT_NOEVENTS) + { + if ($this->doSimpleList($word)) return; + } + $this->addText($word); + } + } + + /** + * Retrieve the current top-level tag to add text into + * @uses $_context + */ + function getContext() + { + array_push($this->_context,$a = array_pop($this->_context)); + return $a; + } + + /** + * Pop a context off of the context stack + * @uses $_context + */ + function dropContext() + { + array_pop($this->_context); + if (count($this->_context) == 0) + $this->_context = array('normal'); + } + + /** + * @uses $_context + * @param string context name + */ + function setContext($context) + { + array_push($this->_context,$context); + } + + /** + * add input as text to the current paragraph or list + * @param string|parserInlineTag + */ + function addText($text) + { + $context = $this->getContext(); + if ($context == 'list') + { +// debug('aded to '.$context); + $this->p_vars['list_item'][$this->p_vars['list_count']]->add($text); + } elseif ($context != 'normal') + { +// debug('added to '.$context); + $this->p_vars[$context]->add($text); + } else + { +// debug('added to normal '); + $indtype = $this->p_vars['indtype']; + if (!isset($this->pars[$this->p_vars['curpar']])) + $this->pars[$this->p_vars['curpar']] = new $indtype; + $this->pars[$this->p_vars['curpar']]->add($text); + } + } + + /**#@-*/ + /**#@+ + * @access private + * @param string|parserInlineTag token from the ObjectWordParser + * @param integer parser event from {@link ParserDescCleanup.inc} + */ + /** + * Handles special case where a description needs the text "" and tag + * is one of code, b, i, pre, var, or any other valid in-DocBlock html tag. + * + * the text <<>> in a DocBlock will parse out as <>, instead + * of being parsed as markup. + */ + function handleEscape($word, $pevent) + { + $this->p_vars['event_stack']->popEvent(); + if (!in_array($word, $this->tokens[PHPDOCUMENTOR_PDP_STATE_ESCAPE])) + { + if ($word == '<') + { + $this->addText($word); + $this->wp->backupPos($word.$word); + } else + $this->wp->backupPos($word); + return; + } + $this->addText('<'.str_replace('>>','>',$word)); + } + + /** + * Just like {@link handleEscape}, except the only valid escape is + * <<

                    >> + */ + function handleEscapePre($word, $pevent) + { + $this->p_vars['event_stack']->popEvent(); + $this->addText('
            '); + } + + /** + * Just like {@link handleEscape}, except the only valid escape is + * <<>> + */ + function handleEscapeCode($word, $pevent) + { + $this->p_vars['event_stack']->popEvent(); + $this->addText(''); + } + + /** + * Handle "<
            >" + * Add a new {@link parserBr} + * @uses addText() + */ + function handleBr($word, $pevent) + { + if (is_string($word) && $this->checkEventPop($word, $pevent)) + { + $this->addText(new parserBr); + } + } + + /** + * Handles simple lists + * + * phpEdit has an ingenious facility to handle simple lists used in a + * DocBlock like this: + * + * - item 1 + * - item 2 + * - item 3 + * + * The DocBlock is: + *
            +     * * - item 1
            +     * * - item 2
            +     * * - item 3
            +     * 
            + * This function converts these simple lists into the parserList class + * @param boolean true if this is the first list item in the list + */ + function handleSimpleList($word, $pevent, $start = false) + { + if (is_object($word) && $this->p_flags['in_item']) + { + $this->p_vars['list_item'][0]->add($word); + return; + } + if (is_string($word) && $this->checkEventPush($word, $pevent)) + { + $this->p_flags['in_event'] = true; + return; + } + $ltrimword = @substr($word, @strpos($word, ltrim($word))); + $is_valid = false; + if (strlen(trim($word)) == 0) + { + if ($this->wp->nextIsObjectOrNonNL()) + { + $is_valid = true; + } + } + if ($word == "\n" && is_string($this->p_vars['last_word']) + && $this->p_vars['last_word']{strlen($this->p_vars['last_word']) - 1} + == "\n") + { + if ($this->p_flags['in_item']) + { + $this->p_vars['lists'][0]->addItem($this->p_vars['list_item'][0]); + unset($this->p_vars['list_item'][0]); + $this->setContext('normal'); + $this->p_flags['simplelist'] = false; + $this->addText($this->p_vars['lists'][0]); + unset($this->p_vars['lists']); + unset($this->p_vars['last_list']); + $this->wp->backuppos($word); + $this->p_vars['event_stack']->popEvent(); + $this->p_flags['in_item'] = false; +// debug('end of list 3'); + return; + } else + { + $this->wp->backuppos($word); + $this->p_vars['event_stack']->popEvent(); + $this->p_flags['in_item'] = false; +// debug('not a list 2'); + return; + } + } + $start_list = $this->getStartList($word); + if (substr($ltrimword,0,strlen($start_list)) != $start_list + || $this->p_flags['in_event'] || is_object($this->p_vars['last_word'])) + { + if (((strlen($this->p_vars['whitespace']) + 1) < strlen(substr($word,0,strpos($word, $ltrimword)))) + || $word == "\n" + || $is_valid + || $this->p_flags['in_event'] + || (is_object($this->p_vars['last_word']) && $this->p_flags['in_item'])) + { + $this->p_vars['list_item'][0]->add($word); + $this->resetStartList($start_list); + $this->p_flags['in_event'] = false; +// debug('middle of list'); + } else + { + if ($this->p_flags['in_item']) + { + $this->p_vars['lists'][0]->addItem($this->p_vars['list_item'][0]); + unset($this->p_vars['list_item'][0]); + $this->setContext('normal'); + $this->p_flags['simplelist'] = false; + $this->addText($this->p_vars['lists'][0]); + unset($this->p_vars['lists']); + unset($this->p_vars['last_list']); + $this->wp->backuppos($word); + $this->p_vars['event_stack']->popEvent(); + $this->p_flags['in_item'] = false; +// debug('end of list 1'); + return; + } else + { + $this->wp->backuppos($word); + $this->p_vars['event_stack']->popEvent(); + $this->p_flags['in_item'] = false; +// debug('not a list'); + return; + } + } + } else + { + if ($this->p_vars['whitespace'] != substr($word,0,strpos($word, $start_list))) + { // if the whitespace is greater than that preceding the list + // delimiter, it's a multi-line list item + $this->setContext('normal'); + $this->p_flags['simplelist'] = false; + $this->addText($this->p_vars['lists'][0]); + unset($this->p_vars['lists']); + $this->wp->backuppos($word); + $this->p_vars['event_stack']->popEvent(); + unset($this->p_vars['last_list']); + $this->p_flags['in_item'] = false; +// debug('end of list 2'); + return; + } else + { + if ($this->p_flags['in_item']) + { + // end of a list item, add it to the list + $this->p_vars['lists'][0]->addItem($this->p_vars['list_item'][0]); + unset($this->p_vars['list_item'][0]); + } +// debug('next list item'); + $this->p_vars['list_item'][0] = new parserStringWithInlineTags; + $this->p_vars['list_item'][0]->add(ltrim(substr($ltrimword,strlen($start_list)))); + $this->p_flags['in_item'] = true; + } + } + } + /**#@-*/ + /** + * Get the next list marker + * + * In unordered lists, this will be something like "o", "-" + * + * In ordered lists, this will be either the number "3", "5" or "3.", "5." + * @return string text of the next list marker to look for + * @param string current word from the parser + * @access private + */ + function getStartList($word) + { + // unordered, return the first marker found + if (!$this->p_flags['orderedlist']) return $this->p_vars['start_list']; + if (isset($this->p_vars['last_list'])) + { + $this->p_vars['save_list'] = $this->p_vars['last_list']; + $next = $this->p_vars['last_list']; + // increment to next list number, convert to string + if (substr($this->p_vars['start_list'], strlen($this->p_vars['start_list']) - 1) == '.') + $next = (substr($next, 0, strpos($next,'.')) + 1) . '.'; + else + $next = ($next + 1) . ''; +// debug("next is '$next'"); + if ($this->p_vars['whitespace'] == substr($word,0,strpos($word, $next))) + return $this->p_vars['last_list'] = $next; + // the next number is not in this word, so return but don't save + return $next; + } else + { + $this->p_vars['last_list'] = $this->p_vars['start_list']; + return $this->p_vars['start_list']; + } + } + + /** + * Set the next list marker to the current list marker + * + * In ordered lists, this will ensure that the next number returned is the + * right number + * @param string token for next list marker + * @access private + */ + function resetStartList($start) + { + if (!isset($this->p_vars['save_list'])) return false; + $this->p_vars['last_list'] = $this->p_vars['save_list']; + } + + /**#@+ + * @access private + * @param string|parserInlineTag token from the ObjectWordParser + * @param integer parser event from {@link ParserDescCleanup.inc} + */ + /** + * Handles <
              >,<
            1. >,<
                > + * + * This allows parsing of lists nested to any level. Using + * the lists and list_item temporary variables and using + * list_count to control nesting, the method creates a {@link parserList} + * for each <
                  > or <
                    > tag, and a + * standard {@link parserStringWithInlineTags} for all the text, adding + * in nested lists as if they were inline tags (the conversion interface + * is the same for both object types) + */ + function handleList($word, $pevent) + { + if (is_string($word) && $this->checkEventPush($word, $pevent)) + { + return; + } + $ordered = false; + if (!is_object($this->p_vars['last_word']) && strtolower($this->p_vars['last_word']) == '
                      ') + { + // ordered list + $ordered = true; + } + // start a new list + if (!is_object($this->p_vars['last_word']) && (strtolower($this->p_vars['last_word']) == '
                        ' || strtolower($this->p_vars['last_word']) == '
                          ')) + { + $this->p_flags['in_item'] = false; + $this->setContext('list'); + $this->p_vars['lists'][++$this->p_vars['list_count']] = new parserList($ordered); + } + if (!is_object($word) && strtolower($word) == '
                        • ') + { + if ($this->p_flags['in_item']) + { + // end of a list item (no end tag), add it to the list + $this->p_vars['lists'][$this->p_vars['list_count']]->addItem($this->p_vars['list_item'][$this->p_vars['list_count']]); + unset($this->p_vars['list_item'][$this->p_vars['list_count']]); + } + // start a new list item + $this->p_vars['list_item'][$this->p_vars['list_count']] = new parserStringWithInlineTags; + $this->p_flags['in_item'] = true; + } else + { + if (is_object($word) || (strtolower($word) != '
                        • ')) + { + if (is_object($word) || (strtolower($word) != '
                        ' && strtolower($word) != '
                      ')) + { + // item text + if (isset($this->p_vars['list_item'][$this->p_vars['list_count']])) + { + if ($word == ' ' && $this->p_vars['last_word'] == ' ') return; + $this->p_vars['list_item'][$this->p_vars['list_count']]->add($word); + } + } else + { + if ($this->p_flags['in_item']) + { + // end the current list item before ending a list + $this->p_vars['lists'][$this->p_vars['list_count']]->addItem($this->p_vars['list_item'][$this->p_vars['list_count']]); + unset($this->p_vars['list_item'][$this->p_vars['list_count']]); + $this->p_flags['in_item'] = false; + } + if (is_string($word) && $this->checkEventPop($word, $pevent)) + { + if ($this->p_vars['list_count'] > 1) + { + // this is a sublist, add it to the list item of the parent list + $this->p_vars['list_item'][$this->p_vars['list_count'] - 1]->add($this->p_vars['lists'][$this->p_vars['list_count']]); + // remove the sublist item and sublist, drop to parent list + unset($this->p_vars['lists'][$this->p_vars['list_count']]); + unset($this->p_vars['lists'][$this->p_vars['list_count']]); + $this->p_vars['list_count']--; + $this->p_flags['in_item'] = true; + } else + { + // this is a primary list and it has concluded + $this->pars[$this->p_vars['curpar']]->add($this->p_vars['lists'][$this->p_vars['list_count']]); + unset($this->p_vars['lists']); + unset($this->p_vars['list_item']); + $this->p_vars['list_count'] = 0; + $this->dropContext(); + } + } + } + } else + { + // check to make sure our list item is not unclosed + if (!$this->p_flags['in_item']) + { + addError(PDERROR_TEXT_OUTSIDE_LI); + } else + { + // end of a list item, add it to the list + $this->p_vars['lists'][$this->p_vars['list_count']]->addItem($this->p_vars['list_item'][$this->p_vars['list_count']]); + unset($this->p_vars['list_item'][$this->p_vars['list_count']]); + $this->p_flags['in_item'] = false; + } + } + } + } + + /** + * Handles <><> blocks + */ + function handleCode($word, $pevent) + { + if (!isset($this->p_vars['my_code'])) + { + $this->setContext('my_code'); + $this->p_vars['my_code'] = new parserCode; + } + if (is_string($word) && $this->checkEventPush($word, $pevent)) return; + if (is_object($word) || strtolower($word) != '
                      ') $this->p_vars['my_code']->add($word); + if (is_string($word)) + { + if ($this->checkEventPop($word,$pevent)) + { + $this->dropContext(); + $this->addText($this->p_vars['my_code']); + unset($this->p_vars['my_code']); + } + } + } + + /** + * Handles <
                      ><
                      > blocks + */ + function handlePre($word, $pevent) + { + if (!isset($this->p_vars['my_pre'])) + { + $this->setContext('my_pre'); + $this->p_vars['my_pre'] = new parserPre; + } + if (is_string($word) && $this->checkEventPush($word, $pevent)) return; + if (is_object($word) || strtolower($word) != '
            ') $this->p_vars['my_pre']->add($word); + if (is_string($word)) + { + if ($this->checkEventPop($word,$pevent)) + { + $this->dropContext(); + $this->addText($this->p_vars['my_pre']); + unset($this->p_vars['my_pre']); + } + } + } + + /** + * Handles <><> blocks + */ + function handleB($word, $pevent) + { + if (!isset($this->p_vars['my_b'])) + { + $this->setContext('my_b'); + $this->p_vars['my_b'] = new parserB; + } + if (is_string($word)) + { + if ($this->checkEventPop($word,$pevent)) + { + $this->dropContext(); + $this->addText($this->p_vars['my_b']); + unset($this->p_vars['my_b']); + } else + { + $this->p_vars['my_b']->add($word); + } + } else $this->p_vars['my_b']->add($word); + } + + /** + * Handles <><> blocks + */ + function handleI($word, $pevent) + { + if (!isset($this->p_vars['my_i'])) + { + $this->p_vars['my_i'] = new parserI; + $this->setContext('my_i'); + } + if (is_string($word)) + { + if ($this->checkEventPop($word,$pevent)) + { + $this->dropContext(); + $this->addText($this->p_vars['my_i']); + unset($this->p_vars['my_i']); + } else + { + $this->p_vars['my_i']->add($word); + } + } else $this->p_vars['my_i']->add($word); + } + + /** + * Handles <><> blocks + */ + function handleVar($word, $pevent) + { + if (!isset($this->p_vars['my_var'])) + { + $this->setContext('my_var'); + $this->p_vars['my_var'] = new parserDescVar; + } + if (is_string($word)) + { + if ($this->checkEventPop($word,$pevent)) + { + $this->dropContext(); + $this->addText($this->p_vars['my_var']); + unset($this->p_vars['my_var']); + } else + { + $this->p_vars['my_var']->add($word); + } + } else $this->p_vars['my_var']->add($word); + } + + /** + * Handles <><> blocks + */ + function handleSamp($word, $pevent) + { + if (!isset($this->p_vars['my_samp'])) + { + $this->setContext('my_samp'); + $this->p_vars['my_samp'] = new parserSamp; + } + if (is_string($word)) + { + if ($this->checkEventPop($word,$pevent)) + { + $this->dropContext(); + $this->addText($this->p_vars['my_samp']); + unset($this->p_vars['my_samp']); + } else + { + $this->p_vars['my_samp']->add($word); + } + } else $this->p_vars['my_samp']->add($word); + } + + /** + * Handles <><> blocks + */ + function handleKbd($word, $pevent) + { + if (!isset($this->p_vars['my_kbd'])) + { + $this->setContext('my_kbd'); + $this->p_vars['my_kbd'] = new parserKbd; + } + if (is_string($word)) + { + if ($this->checkEventPop($word,$pevent)) + { + $this->dropContext(); + $this->addText($this->p_vars['my_kbd']); + unset($this->p_vars['my_kbd']); + } else + { + $this->p_vars['my_kbd']->add($word); + } + } else $this->p_vars['my_kbd']->add($word); + } + + /** + * Handles <

            ><

            > blocks + * + * Note that the only time <

            > will be interpreted as delimiting a + * paragraph is if it is the first thing in the description. + */ + function handleP($word, $pevent) + { + if (!isset($this->parse_Ps)) $this->parse_Ps = false; + if (is_string($word)) + { + if (is_string($word) && $this->checkEventPush($word, $pevent)) return; + } + if (!$this->parse_Ps) + { + $this->p_vars['event_stack']->popEvent(); + if (!is_object($word) && strtolower($this->p_vars['last_word']) == '

            ') $this->addText('

            '); + $this->addText($word); + return; + } + if ($word == "\n") $word = " "; + if (is_string($word)) + { + if ($this->checkEventPop($word, $pevent)) + { + $this->p_vars['curpar']++; + return; + } + // if no closing tag, pretend there was one + if (!is_object($word) && strtolower($word) == '

            ' && $this->parse_Ps) + { + $this->p_vars['curpar']++; + return; + } + } + if ($this->p_vars['start']) + { + $this->addText($word); + } else + {// if the

            is not at the beginning of the desc, then it is not + // possible to parse into paragraphs using this tag + if ($word == ' ' && $this->p_vars['last_word'] == ' ') return; + $this->addText($word); + } + } + + /** + * Handles \n\n as a paragraph marker + * @uses doSimpleList() + */ + function handleDoubleCR($word, $pevent) + { + $this->p_vars['event_stack']->popEvent(); + if ($word == "\n") + { + // only use this if

            isn't being used + if ((!isset($this->parse_Ps) || !$this->parse_Ps)) + { + if ($this->p_vars['last_word'] == "\n") + { + $this->p_vars['curpar']++; + $this->parse_Ps = false; + } else + { + if (is_string($word) && !$this->checkEventPush($word, $pevent)) + { + if ($word == ' ' && $this->p_vars['last_word'] == ' ') return; + $this->addText($word); + } + } + } else + { + if (is_string($word) && !$this->checkEventPush($word, $pevent)) + { + if ($word == ' ' && $this->p_vars['last_word'] == ' ') return; + $this->addText($word); + } + } + } else + { + if ($this->p_vars['last_word'] == "\n") + { + if ((!isset($this->parse_Ps) || !$this->parse_Ps)) + { + $this->addText(' '); + } + } + if (is_string($word) && !($e = $this->checkEventPush($word, $pevent))) + { + if ($word == ' ' && $this->p_vars['last_word'] == ' ') return; + if ($this->doSimpleList($word)) return; + $this->addText($word); + } + } + } + + /**#@-*/ + /** + * Return a simple list, if found + * + * This helper function extracts a simple list beginning with any of + * 'o','-'.'#','+','0','1','0.','1.' and starts parsing it. + * @param string line that may contain a simple list + * @return boolean true if a list is found, false otherwise + */ + function doSimpleList($word) + { + if ($this->p_flags['in_event']) return true; + if (is_object($word)) return false; + $ltrimword = ltrim($word); + if ((strlen($ltrimword) != strlen($word)) + && strlen($ltrimword) > 1 + && ((in_array($ltrimword{0},array('o','-','1','0','#','+')) && $ltrimword{1} == ' ')) + || ((strlen($ltrimword) >= 2) && (in_array(substr($ltrimword,0,2),array('1.','0.')) && $ltrimword{2} == ' '))) + { + // save the whitespace for comparison + $this->p_vars['whitespace'] = substr($word,0,strlen($word) - strlen($ltrimword)); + $this->p_vars['start_list'] = $ltrimword{0}; + if ($this->p_vars['start_list'] != '1' && $this->p_vars['start_list'] != '1.' && + $this->p_vars['start_list'] != '0' && $this->p_vars['start_list'] != '0.') + { + $this->p_flags['orderedlist'] = false; + } else + { + if (substr($ltrimword,0,2) == '1.') + { + $this->p_vars['start_list'] = '1.'; + } + $this->p_flags['orderedlist'] = true; + } + $this->p_vars['event_stack']->pushEvent(PHPDOCUMENTOR_PDP_EVENT_SIMLIST); + $this->setContext('list'); + $this->p_flags['simplelist'] = true; + $this->p_vars['lists'][0] = new parserList($this->p_flags['orderedlist']); + $this->p_vars['list_count'] = 0; + $this->handleSimpleList($word, PHPDOCUMENTOR_PDP_EVENT_SIMLIST, true); + return true; + } + return false; + } + /** + * setup the parser tokens, and the pushEvent/popEvent arrays + * @see $tokens, $pushEvent, $popEvent + * @param boolean determines whether to allow paragraph parsing + * @global boolean used to determine whether to slow things down or not by + * eliminating whitespace from comments + */ + + function setupStates($sdesc) + { + $this->p_flags['in_item'] = false; + $this->p_flags['in_event'] = false; + $this->p_flags['simplelist'] = false; + $this->_context = array('normal'); + $this->tokens[STATE_NOEVENTS] = array("\n", "", "

            ", "
              ", "
                ", + "", "", '', '', '', "tokens[STATE_NOEVENTS][] = "

                "; + $this->tokens[STATE_NOEVENTS][] = "

                "; + } + if (PHPDOCUMENTOR_KILL_WHITESPACE) $this->tokens[STATE_NOEVENTS][] = ' '; + $this->tokens[PHPDOCUMENTOR_PDP_STATE_P] = array("

                ","","
                ", '<
                ","\n","
                  ","
                    ","","","", '<<', + '', '', ''); + if (PHPDOCUMENTOR_KILL_WHITESPACE) $this->tokens[PHPDOCUMENTOR_PDP_STATE_P][] = ' '; + $this->tokens[PHPDOCUMENTOR_PDP_STATE_CODE] = array("", '<>'); + $this->tokens[PHPDOCUMENTOR_PDP_STATE_PRE] = array("
            >'); + $this->tokens[PHPDOCUMENTOR_PDP_STATE_LIST] = array("
              ","
                ","
            ","
        ","
      • ","
      • ","","","","
        ","', '', '');
        +        $this->tokens[PHPDOCUMENTOR_PDP_STATE_DOUBLECR]        = array("\n","
          ","
            ","","
            ","","","","

            ", + '', '', '', '<<'); + $this->tokens[PHPDOCUMENTOR_PDP_STATE_SIMLIST] = array("\n",'', '', '','','', '
            ', '',
            +                                                                    'tokens[PHPDOCUMENTOR_PDP_STATE_B]    = array("","\n","
            ","
              ","
                ","","","', '', ''); + $this->tokens[PHPDOCUMENTOR_PDP_STATE_KBD] = array("","\n","
                ","
                  ","
                    ","","","', '', ''); + $this->tokens[PHPDOCUMENTOR_PDP_STATE_VAR] = array("","\n","
                    ","
                      ","
                        ","","","', '', ''); + $this->tokens[PHPDOCUMENTOR_PDP_STATE_SAMP] = array("","\n","
                        ","
                          ","
                            ","","","', '', ''); + $this->tokens[PHPDOCUMENTOR_PDP_STATE_I] = array("","\n","
                            ","
                              ","
                                ","","","', '', ''); + $this->tokens[PHPDOCUMENTOR_PDP_STATE_BR] = array(">","/>"); + $this->tokens[PHPDOCUMENTOR_PDP_STATE_ESCAPE] = array('code>>', '/code>>', 'pre>>', '/pre>>', 'b>>', '/b>>', + 'i>>', '/i>>', 'ol>>', '/ol>>', 'ul>>', '/ul>>', + 'br>>', 'br />>', 'p>>', '/p>>', 'samp>>', '/samp>>', + 'kbd>>', '/kbd>>', 'var>>', '/var>>'); + if (PHPDOCUMENTOR_KILL_WHITESPACE) $this->tokens[PHPDOCUMENTOR_PDP_STATE_DOUBLECR][] = ' '; + + // For each event word to event mapings + $this->pushEvent[PARSER_EVENT_NOEVENTS] = + array( + "" => PHPDOCUMENTOR_PDP_EVENT_CODE, + ">' => PHPDOCUMENTOR_PDP_EVENT_ESCAPE_PRE, + ); + + $this->popEvent[PHPDOCUMENTOR_PDP_EVENT_PRE] = array("
                                "    => PHPDOCUMENTOR_PDP_EVENT_PRE,
                                +                "

                                " => PHPDOCUMENTOR_PDP_EVENT_P, + "" => PHPDOCUMENTOR_PDP_EVENT_VAR, + "" => PHPDOCUMENTOR_PDP_EVENT_SAMP, + "" => PHPDOCUMENTOR_PDP_EVENT_KBD, + "

                                  " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "
                                    " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "" => PHPDOCUMENTOR_PDP_EVENT_B, + "" => PHPDOCUMENTOR_PDP_EVENT_I, + " PHPDOCUMENTOR_PDP_EVENT_BR, + "\n" => PHPDOCUMENTOR_PDP_EVENT_DOUBLECR, + '<<' => PHPDOCUMENTOR_PDP_EVENT_ESCAPE, + ); +########################## + $this->pushEvent[PHPDOCUMENTOR_PDP_EVENT_CODE] = + array( + '<>' => PHPDOCUMENTOR_PDP_EVENT_ESCAPE_CODE, + ); + + $this->popEvent[PHPDOCUMENTOR_PDP_EVENT_CODE] = array(""); +########################## + $this->pushEvent[PHPDOCUMENTOR_PDP_EVENT_PRE] = + array( + '<
                            "); +########################## + + $this->popEvent[PHPDOCUMENTOR_PDP_EVENT_BR] = array(">","/>"); +########################## + $this->pushEvent[PHPDOCUMENTOR_PDP_EVENT_P] = + array( + "" => PHPDOCUMENTOR_PDP_EVENT_CODE, + "
                              " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "
                                " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "" => PHPDOCUMENTOR_PDP_EVENT_VAR, + "" => PHPDOCUMENTOR_PDP_EVENT_SAMP, + "" => PHPDOCUMENTOR_PDP_EVENT_KBD, + "
                                " => PHPDOCUMENTOR_PDP_EVENT_PRE,
                                +                "" => PHPDOCUMENTOR_PDP_EVENT_B,
                                +                "" => PHPDOCUMENTOR_PDP_EVENT_I,
                                +                " PHPDOCUMENTOR_PDP_EVENT_BR,
                                +                '<<' => PHPDOCUMENTOR_PDP_EVENT_ESCAPE,
                                +            );
                                +         
                                +        $this->popEvent[PHPDOCUMENTOR_PDP_EVENT_P] = array("

                                "); +########################## + + $this->pushEvent[PHPDOCUMENTOR_PDP_EVENT_LIST] = + array( + "
                                  " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "
                                    " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "" => PHPDOCUMENTOR_PDP_EVENT_CODE, + "" => PHPDOCUMENTOR_PDP_EVENT_VAR, + "" => PHPDOCUMENTOR_PDP_EVENT_SAMP, + "" => PHPDOCUMENTOR_PDP_EVENT_KBD, + "" => PHPDOCUMENTOR_PDP_EVENT_B, + "" => PHPDOCUMENTOR_PDP_EVENT_I, + "
                                    " => PHPDOCUMENTOR_PDP_EVENT_PRE,
                                    +                " PHPDOCUMENTOR_PDP_EVENT_BR,
                                    +                '<<' => PHPDOCUMENTOR_PDP_EVENT_ESCAPE,
                                    +            );
                                    +        
                                    +        $this->popEvent[PHPDOCUMENTOR_PDP_EVENT_LIST] = array("
                                ","
                            "); +########################## + + $this->pushEvent[PHPDOCUMENTOR_PDP_EVENT_SIMLIST] = + array( + "" => PHPDOCUMENTOR_PDP_EVENT_CODE, + "
                            "    => PHPDOCUMENTOR_PDP_EVENT_PRE,
                            +                "

                            " => PHPDOCUMENTOR_PDP_EVENT_P, + "" => PHPDOCUMENTOR_PDP_EVENT_VAR, + "" => PHPDOCUMENTOR_PDP_EVENT_SAMP, + "" => PHPDOCUMENTOR_PDP_EVENT_KBD, + "" => PHPDOCUMENTOR_PDP_EVENT_B, + "" => PHPDOCUMENTOR_PDP_EVENT_I, + " PHPDOCUMENTOR_PDP_EVENT_BR, + '<<' => PHPDOCUMENTOR_PDP_EVENT_ESCAPE, + ); +########################## + + $this->pushEvent[PHPDOCUMENTOR_PDP_EVENT_DOUBLECR] = + array( + "" => PHPDOCUMENTOR_PDP_EVENT_CODE, + "

                              " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "
                                " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "
                                " => PHPDOCUMENTOR_PDP_EVENT_PRE,
                                +                "" => PHPDOCUMENTOR_PDP_EVENT_B,
                                +                "" => PHPDOCUMENTOR_PDP_EVENT_I,
                                +                "" => PHPDOCUMENTOR_PDP_EVENT_VAR,
                                +                "" => PHPDOCUMENTOR_PDP_EVENT_SAMP,
                                +                "" => PHPDOCUMENTOR_PDP_EVENT_KBD,
                                +                " PHPDOCUMENTOR_PDP_EVENT_BR,
                                +                "

                                " => PHPDOCUMENTOR_PDP_EVENT_P, + '<<' => PHPDOCUMENTOR_PDP_EVENT_ESCAPE, + ); + +########################## + $this->pushEvent[PHPDOCUMENTOR_PDP_EVENT_B] = + array( + "" => PHPDOCUMENTOR_PDP_EVENT_CODE, + "

                                  " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "
                                    " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "
                                    " => PHPDOCUMENTOR_PDP_EVENT_PRE,
                                    +                "" => PHPDOCUMENTOR_PDP_EVENT_VAR,
                                    +                "" => PHPDOCUMENTOR_PDP_EVENT_SAMP,
                                    +                "" => PHPDOCUMENTOR_PDP_EVENT_KBD,
                                    +                " PHPDOCUMENTOR_PDP_EVENT_BR,
                                    +                '' => PHPDOCUMENTOR_PDP_EVENT_I,
                                    +                '<<' => PHPDOCUMENTOR_PDP_EVENT_ESCAPE,
                                    +            );
                                    +         
                                    +        $this->popEvent[PHPDOCUMENTOR_PDP_EVENT_B] = array("");
                                    +
                                    +##########################
                                    +        $this->pushEvent[PHPDOCUMENTOR_PDP_EVENT_I] =
                                    +            array(
                                    +                "" => PHPDOCUMENTOR_PDP_EVENT_CODE,
                                    +                "
                                      " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "
                                        " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "
                                        " => PHPDOCUMENTOR_PDP_EVENT_PRE,
                                        +                "" => PHPDOCUMENTOR_PDP_EVENT_VAR,
                                        +                "" => PHPDOCUMENTOR_PDP_EVENT_SAMP,
                                        +                "" => PHPDOCUMENTOR_PDP_EVENT_KBD,
                                        +                " PHPDOCUMENTOR_PDP_EVENT_BR,
                                        +                '' => PHPDOCUMENTOR_PDP_EVENT_B,
                                        +                '<<' => PHPDOCUMENTOR_PDP_EVENT_ESCAPE,
                                        +            );
                                        +         
                                        +        $this->popEvent[PHPDOCUMENTOR_PDP_EVENT_I] = array("");
                                        +
                                        +##########################
                                        +        $this->pushEvent[PHPDOCUMENTOR_PDP_EVENT_VAR] =
                                        +            array(
                                        +                "" => PHPDOCUMENTOR_PDP_EVENT_CODE,
                                        +                "
                                          " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "
                                            " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "
                                            " => PHPDOCUMENTOR_PDP_EVENT_PRE,
                                            +                "" => PHPDOCUMENTOR_PDP_EVENT_I,
                                            +                "" => PHPDOCUMENTOR_PDP_EVENT_SAMP,
                                            +                "" => PHPDOCUMENTOR_PDP_EVENT_KBD,
                                            +                " PHPDOCUMENTOR_PDP_EVENT_BR,
                                            +                '' => PHPDOCUMENTOR_PDP_EVENT_B,
                                            +                '<<' => PHPDOCUMENTOR_PDP_EVENT_ESCAPE,
                                            +            );
                                            +         
                                            +        $this->popEvent[PHPDOCUMENTOR_PDP_EVENT_VAR] = array("");
                                            +
                                            +##########################
                                            +        $this->pushEvent[PHPDOCUMENTOR_PDP_EVENT_SAMP] =
                                            +            array(
                                            +                "" => PHPDOCUMENTOR_PDP_EVENT_CODE,
                                            +                "
                                              " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "
                                                " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "
                                                " => PHPDOCUMENTOR_PDP_EVENT_PRE,
                                                +                "" => PHPDOCUMENTOR_PDP_EVENT_VAR,
                                                +                "" => PHPDOCUMENTOR_PDP_EVENT_I,
                                                +                "" => PHPDOCUMENTOR_PDP_EVENT_KBD,
                                                +                " PHPDOCUMENTOR_PDP_EVENT_BR,
                                                +                '' => PHPDOCUMENTOR_PDP_EVENT_B,
                                                +                '<<' => PHPDOCUMENTOR_PDP_EVENT_ESCAPE,
                                                +            );
                                                +         
                                                +        $this->popEvent[PHPDOCUMENTOR_PDP_EVENT_SAMP] = array("");
                                                +
                                                +##########################
                                                +        $this->pushEvent[PHPDOCUMENTOR_PDP_EVENT_KBD] =
                                                +            array(
                                                +                " PHPDOCUMENTOR_PDP_EVENT_CODE,
                                                +                "
                                                  " => PHPDOCUMENTOR_PDP_EVENT_LIST, + "
                                                    " => PHPDOCUMENTOR_PDP_EVENT_LIST, + " PHPDOCUMENTOR_PDP_EVENT_PRE, + "" => PHPDOCUMENTOR_PDP_EVENT_VAR, + "" => PHPDOCUMENTOR_PDP_EVENT_SAMP, + "" => PHPDOCUMENTOR_PDP_EVENT_I, + " PHPDOCUMENTOR_PDP_EVENT_BR, + '' => PHPDOCUMENTOR_PDP_EVENT_B, + '<<' => PHPDOCUMENTOR_PDP_EVENT_ESCAPE, + ); + + $this->popEvent[PHPDOCUMENTOR_PDP_EVENT_KBD] = array(""); + } + + function getParserEventName ($value) + { + $lookup = array( + PARSER_EVENT_NOEVENTS => "PARSER_EVENT_NOEVENTS", + PHPDOCUMENTOR_PDP_EVENT_CODE => "PHPDOCUMENTOR_PDP_EVENT_CODE", + PHPDOCUMENTOR_PDP_EVENT_P => "PHPDOCUMENTOR_PDP_EVENT_P", + PHPDOCUMENTOR_PDP_EVENT_B => "PHPDOCUMENTOR_PDP_EVENT_B", + PHPDOCUMENTOR_PDP_EVENT_I => "PHPDOCUMENTOR_PDP_EVENT_I", + PHPDOCUMENTOR_PDP_EVENT_BR => "PHPDOCUMENTOR_PDP_EVENT_BR", + PHPDOCUMENTOR_PDP_EVENT_VAR => "PHPDOCUMENTOR_PDP_EVENT_VAR", + PHPDOCUMENTOR_PDP_EVENT_SAMP => "PHPDOCUMENTOR_PDP_EVENT_SAMP", + PHPDOCUMENTOR_PDP_EVENT_KBD => "PHPDOCUMENTOR_PDP_EVENT_KBD", + PHPDOCUMENTOR_PDP_EVENT_ESCAPE => "PHPDOCUMENTOR_PDP_EVENT_ESCAPE", + PHPDOCUMENTOR_PDP_EVENT_ESCAPE_CODE => "PHPDOCUMENTOR_PDP_EVENT_ESCAPE_CODE", + PHPDOCUMENTOR_PDP_EVENT_ESCAPE_PRE => "PHPDOCUMENTOR_PDP_EVENT_ESCAPE_PRE", + PHPDOCUMENTOR_PDP_EVENT_DOUBLECR => "PHPDOCUMENTOR_PDP_EVENT_DOUBLECR", + PHPDOCUMENTOR_PDP_EVENT_LIST => "PHPDOCUMENTOR_PDP_EVENT_LIST", + PHPDOCUMENTOR_PDP_EVENT_PRE => "PHPDOCUMENTOR_PDP_EVENT_PRE", + PHPDOCUMENTOR_PDP_EVENT_SIMLIST => "PHPDOCUMENTOR_PDP_EVENT_SIMLIST", + ); + if (isset($lookup[$value])) + return $lookup[$value]; + else return $value; + } +} + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/ParserDocBlock.inc b/buildscripts/PhpDocumentor/phpDocumentor/ParserDocBlock.inc new file mode 100644 index 00000000..96ea1b20 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/ParserDocBlock.inc @@ -0,0 +1,1165 @@ + + * @since 1.0rc1 + * @version $Id: ParserDocBlock.inc,v 1.1 2005/10/17 18:36:57 jeichorn Exp $ + */ +class parserDesc extends parserStringWithInlineTags +{ + /** + * Type is used by many functions to skip the hassle of if phpDocumentor_get_class($blah) == 'parserBlah' + * always '_desc' + * @var string + */ + var $type = '_desc'; + + /** + * @param mixed like {@link parserStringWithInlineTags::add()}, this can be a string or parserInlineTag, but it can also be a + * parserStringWithInlineTags, and the contents will be merged + */ + function add($stringOrClass) + { + if (is_object($stringOrClass)) + { + if (phpDocumentor_get_class($stringOrClass) == 'parserstringwithinlinetags' || + phpDocumentor_get_class($stringOrClass) == 'parserdesc') + { + for($i=0;$ivalue);$i++) + { + parserStringWithInlineTags::add($stringOrClass->value[$i]); + } + } else + { + parserStringWithInlineTags::add($stringOrClass); + } + } else return parserStringWithInlineTags::add($stringOrClass); + } + + /** + * @return boolean whether this desc has an {@}inheritdoc} inline tag + */ + function hasInheritDoc() + { + for($i=0;$ivalue);$i++) + { + if (phpDocumentor_get_class($this->value[$i])=='parserinheritdocinlinetag') return true; + } + } + + /** + * @return boolean whether this desc has an {@}source} inline tag + */ + function hasSource() + { + for($i=0;$ivalue);$i++) + { + if (phpDocumentor_get_class($this->value[$i])=='parsersourceinlinetag') return true; + } + } + + /** + * replaces {@}inheritdoc} with the contents of the parent DocBlock + * @param parserDesc parent parserDesc, used to retrieve the description + */ + function replaceInheritDoc($desc) + { + $value = $this->value; + $this->value = array(); + for($i=0;$ivalue);$j++) + { + $this->add($desc->value[$j]); + } + } else $this->add($value[$i]); + } + } +} + +/** + * Represents a docblock and its components, {@link $desc}, {@link $sdesc}, {@link $tags}, and also {@link $params} for functions + * @package phpDocumentor + * @subpackage ParserDocBlock + * @author Greg Beaver + * @since 1.0rc1 + * @version $Id: ParserDocBlock.inc,v 1.1 2005/10/17 18:36:57 jeichorn Exp $ + */ +class parserDocBlock +{ + /** + * @var parserDesc + */ + var $desc = false; + /** + * @var array array of {@link parserDesc}s + */ + var $processed_desc = false; + /** + * @var array array of {@link parserDesc}s + */ + var $processed_sdesc = false; + /** + * @var parserDesc + */ + var $sdesc = false; + /** + * Line number in the source on which this docblock begins + * @since 1.2 + * @var false|integer + */ + var $linenumber = false; + /** + * Line number in the source on which this docblock ends + * @since 1.2 + * @var false|integer + */ + var $endlinenumber = false; + /** + * array of {@link parserTag}s + * @var array + */ + var $tags = array(); + /** + * array of unrecognized {@link parserTag}s + * @var array + */ + var $unknown_tags = array(); + /** + * array of param data. + * Format: + * array(index of param in function parameter list -OR- parameter name => + * parserStringWithInlineTags,...) + * @var array + */ + var $params = array(); + /** + * array of global variable data. + * Format: + * array(index of global variable in @global tag list -OR- global variable name => + * array(datatype,parserStringWithInlineTags),...) + * @var array + */ + var $funcglobals = array(); + + /** + * array of static variable data. + * Format: + * array(index of static variable in @global tag list -OR- static variable name => + * {@link parserStaticvarTag},...) + * @var array + */ + var $statics = array(); + /** + * This is either a {@link parserReturnTag} or false if no return tag is present + * @var mixed + */ + var $return = false; + /** + * This is either a {@link parserVarTag} or false if no var tag is present + * @var mixed + */ + var $var = false; + /** + * fix for bug 591396 + * @var boolean + */ + var $explicitpackage = false; + /** + * fix for bug 708559 + * @var boolean + */ + var $explicitcategory = false; + /** @var string */ + var $category; + /** @var string */ + var $package = 'default'; + /** @var string */ + var $subpackage = ''; + /** + * whether this DocBlock has an @access tag + * @var boolean */ + var $hasaccess = false; + /** + * whether this DocBlock has a @name tag + * @var boolean */ + var $hasname = false; + /** + * description of package parsed from @package tag + * Unused in this version + * @var string + */ + var $packagedescrip = ''; + /** + * description of subpackage parsed from @package tag + * Unused in this version + * @var string + */ + var $subpackagedescrip = ''; + /** + * Determines whether a DocBlock can legally have a {@}source} tag + * @tutorial tags.inlinesource.pkg + * @var boolean + * @access private + */ + var $_canSource = false; + + /** + * sets package to default + * @global string default package name + */ + function parserDocBlock() + { + global $phpDocumentor_DefaultPackageName; + $this->package = $GLOBALS['phpDocumentor_DefaultPackageName']; + $this->category = $GLOBALS['phpDocumentor_DefaultCategoryName']; + } + + /** + * Sets the starting line number for the DocBlock + * @param integer + */ + function setLineNumber($number) + { + $this->linenumber = $number; + } + + /** + * Retrieve starting line number + * @return integer + */ + function getLineNumber() + { + return $this->linenumber; + } + + /** + * Sets the ending line number for the DocBlock + * @param integer + */ + function setEndLineNumber($number) + { + $this->endlinenumber = $number; + } + + /** + * Retrieve ending line number + * @return integer + */ + function getEndLineNumber() + { + return $this->endlinenumber; + } + + /** + * Parse out any html tags from doc comments, and make them into + * abstract structures + * @uses parserDescParser::parse() + */ + function postProcess() + { + if ($this->sdesc) + { + $parser = new parserDescParser; + $parser->subscribe('*',$this); + if ($this->desc) $parser->parse($this->desc->value); + $parser->parse($this->sdesc->value,true); + } + } + + /** + * Tells the DocBlock it can have a @filesource tag + * + * Only page-level DocBlocks may have a @filesource tag + */ + function canSource() + { + $this->_canSource = true; + } + + /** + * Tells the DocBlock it can't have a @filesource tag + * + * Only page-level DocBlocks may have a @filesource tag + */ + function cantSource() + { + $this->_canSource = false; + } + + /** + * Indirectly called after parsing by {@link postProcess} + * + * @param integer either 1 for long desc or 2 for short desc + * @param array data organized into paragraphs. Each entry is a {@link parserStringWithInlineTags} + * @uses $processed_desc sets to the array passed from {@link parserDescParser::parse()} + * @uses $processed_sdesc sets to the array passed from {@link parserDescParser::parse()} + * @access private + */ + function HandleEvent($event,$data) + { + if ($event == 1) + $this->processed_desc = $data; + else + $this->processed_sdesc = $data; + } + + /** + * @param array + */ + function updateModifiers($modifiers) + { + if (is_array($modifiers) && count($modifiers)) + { + foreach ($modifiers as $modifier) + { + switch ($modifier) + { + case 'private' : + case 'public' : + case 'protected' : + unset($this->tags['access']); + $x = new parserAccessTag($modifier); + if ($x->isvalid) + { + $this->hasaccess = true; + $this->tags['access'][] = $x; + } + break; + case 'static' : + case 'abstract' : + unset($this->tags[$modifier]); + $this->addKeyword($modifier, ''); + break; + } + } + } + } + + /** + * Set the short description of the DocBlock + * + * Setting the short description is possible by passing in one of three + * possible parameters: + *
                                                      + *
                                                    • another DocBlock's short description
                                                    • + *
                                                    • another DocBlock, the short description will be extracted
                                                    • + *
                                                    • a Zend Studio-compatible @desc tag
                                                    • + *
                                                    + * @param parserDesc|parserDocBlock|parserTag sets {@link $sdesc} + */ + function setShortDesc($desc) + { + if (phpDocumentor_get_class($desc) == 'parsertag') + { + $this->sdesc = new parserDesc; + $this->processed_sdesc = $desc->value; + return; + } + if (phpDocumentor_get_class($desc) == 'parserdesc') { + $this->sdesc = $desc; + } else + { + $this->sdesc = $desc->sdesc; + $this->processed_sdesc = $desc->processed_sdesc; + } + + if ($this->sdesc && $this->sdesc->hasSource()) + { + addWarning(PDERROR_SOURCE_TAG_IGNORED,$this->sdesc->getString()); + } + } + + /** + * Passes to {@link parserStringWithInlineTags::setSource()} + * + * After passing, it calls {@link postProcess()} to set up the new + * source + * @param string|array tokenized highlight-ready source code + * @param false|string name of class if this is a method source + */ + function setSource($source, $class = false) + { + if ($this->desc) + { + $this->desc->setSource($source, $class); + $this->postProcess(); + } + } + + /** + * @param parserDesc|parserDocBlock sets {@link $desc} + */ + function setDesc($desc) + { + if (phpDocumentor_get_class($desc) == 'parserdesc') + $this->desc = $desc; + else + { + $this->desc = $desc->desc; + $this->processed_desc = $desc->processed_desc; + } + } + + /** + * Wrapper for {@link parserDesc::hasInheritDoc()} + * @return boolean + */ + function hasInheritDoc() + { + if (!$this->desc) return false; + return $this->desc->hasInheritDoc(); + } + + /** + * Wrapper for {@link parserDesc::replaceInheritDoc()} + * + * Also replaces {@}inheritdoc} in the {@link $processed_desc} + * @param parserDesc + */ + function replaceInheritDoc($desc) + { + if (!$this->desc) return false; + $this->desc->replaceInheritDoc($desc->desc); + $this->postProcess(); + } + + /** + * @param Converter takes {@link $sdesc} and converts it to a string and returns it if present, otherwise returns '' + * @return string + */ + function getSDesc(&$converter) + { + if ($this->sdesc && $this->processed_sdesc) + { + $result = ''; + foreach($this->processed_sdesc as $desc) + { + if (count($desc->value)) + $result .= $desc->Convert($converter); + } + return $result; + } else + { +// var_dump($this->desc,$this->processed_desc); + } + return ''; + } + + /** + * @param Converter takes {@link $desc} and converts it to a string and returns it if present, otherwise returns '' + * @return string + */ + function getDesc(&$converter) + { + if ($this->desc && $this->processed_desc) + { + $result = ''; + foreach($this->processed_desc as $desc) + { + if (count($desc->value)) + $result .= $converter->EncloseParagraph($desc->Convert($converter)); + } + return $result; + } else + { +// var_dump($this->desc,$this->processed_desc); + } + return ''; + } + + /** + * @param string $paramVar if empty, param is indexed in the order received and set using {@link changeParam()} + * @param parserStringWithInlineTags $value + */ + function addParam($paramVar, $paramType, $value) + { + if (empty($paramVar)) + $this->params[count($this->params)] = new parserParamTag($paramType,$value); + else + $this->params[$paramVar] = new parserParamTag($paramType,$value); + } + + /** + * @param integer $index index of parameter in the {@link $params} array + * @param string $name name of the parameter to set in the $params array + */ + function changeParam($index,$name) + { + $this->params[$name] = $this->params[$index]; + unset($this->params[$index]); + } + + /** + * replaces nameless parameters in the {@link $params} array with their names + * @param array $params Format: array(parameter index => parameter name,...) + */ + function updateParams($params) + { + for($i=0;$iparams[$i])) + { + $this->changeParam($i,$params[$i]); + } + } + if (isset($this->tags)) + unset($this->tags['param']); + } + + /** + * Used to insert DocBlock Template tags into a docblock + * @param parserTag tag + * @global array used to determine whether to add ignored tags, or not + */ + function addTag($tag) + { + global $_phpDocumentor_setting; + if (phpDocumentor_setup::checkIgnoreTag($tag->keyword)) return; + $value = $tag->value; + if (is_array($value)) $value = $value[0]; + if ($tag->keyword == 'uses') + { + $this->addUses($value, $tag->_description); + } else + { + $this->addKeyword($tag->keyword, $value); + } + } + + /** + * @param string $keyword tag name + * @param parserStringWithInlineTags $value the contents of the tag + * @global array used to determine whether to add the @internal tag or not + */ + function addKeyword($keyword, $value) + { + global $_phpDocumentor_setting; + if (phpDocumentor_setup::checkIgnoreTag($keyword)) return; + // don't add the tag at all if it was specified to ignore it with --ignore-tags + if ($keyword == 'package' || $keyword == 'subpackage' || $keyword == 'category') return $this->addPackage($keyword, $value); + if ($keyword == 'access') return $this->addAccess($value); + if ($keyword == 'link') return $this->addLink($value); + if ($keyword == 'see' || $keyword == 'tutorial') return $this->addSee($keyword,$value); + if ($keyword == 'uses') return $this->addUses($keyword, $value); + if ($keyword == 'name') return $this->addName($value); + if (!in_array($keyword,$GLOBALS['_phpDocumentor_tags_allowed'])) + $this->addUnknownTag($keyword,$value); + else + { + if ($keyword == 'internal' && (!isset($_phpDocumentor_setting['parseprivate']) || $_phpDocumentor_setting['parseprivate'] == 'off')) return; + if (!isset($this->tags[$keyword])) { + $this->tags[$keyword] = array(); + } + $ptag = 'parserTag'; + if (class_exists('parser'.$keyword.'tag')) + $ptag = 'parser'.ucfirst($keyword).'Tag'; + array_unshift($this->tags[$keyword], new $ptag($keyword, $value)); + } + } + + /** + * adds an @example tag + * @param string contents of the tag + * @param string path to the file containing this tag + */ + function addExample($value, $path) + { + $this->tags['example'][] = new parserExampleTag($value, $path); + } + + /** + * adds an unknown tag to the {@link $unknown_tags} array for use by custom converters + * @param string tag name + * @param string tag value + */ + function addUnknownTag($keyword, $value) + { + addWarning(PDERROR_UNKNOWN_TAG,$keyword); + $this->unknown_tags[$keyword][] = new parserTag($keyword, $value); + } + + /** + * set the element's package to the passed values. Used in {@link phpDocumentor_IntermediateParser} to align package of + * elements inside a class or procedural page to the package of the class/procedural page + * @param string + * @param string + * @param string + * @param string element name + * @param string element type (include, define, var, method, global, function, const) + */ + function overridePackage($category, $package,$subpackage,$elname,$type) + { + if ($this->package != $GLOBALS['phpDocumentor_DefaultPackageName']) + { + addError(PDERROR_OVERRIDDEN_PACKAGE_TAGS,$elname,$type,$this->package); + $this->explicitpackage = false; + } + if (!empty($this->subpackage)) + addError(PDERROR_OVERRIDDEN_SUBPACKAGE_TAGS,$type,$elname,$this->subpackage); + $this->package = $GLOBALS['phpDocumentor_DefaultPackageName']; + $this->subpackage = ''; + $this->category = $category; + $this->addPackage('package',$package); + $this->addPackage('subpackage',$subpackage); + } + + /** + * Used if this docblock has a @package tag. + * + * phpDocumentor will guess package for DocBlocks that don't have + * a @package tag + * @uses $explicitpackage + */ + function setExplicitPackage() + { + $this->explicitpackage = true; + } + + /** + * If the DocBlock has a @package tag, then this returns true + * @return boolean + */ + function getExplicitPackage() + { + return $this->explicitpackage; + } + + /** + * Used if this docblock has a @category tag. + * + * phpDocumentor will guess category for DocBlocks that don't have + * a @category tag + * @uses $explicitcategory + */ + function setExplicitCategory() + { + $this->explicitcategory = true; + } + + /** + * If the DocBlock has a @category tag, then this returns true + * @return boolean + */ + function getExplicitCategory() + { + return $this->explicitcategory; + } + + /** + * @param string $keyword tag name (either package or subpackage) + * @param mixed $value either a string or a parserStringWithInlineTags. Strips all inline tags and use the text as the package + */ + function addPackage($keyword, $value) + { + if ($keyword == 'package') + { + if (!$this->explicitpackage) + { + if (!is_string($value)) + $value = $value->getString(); + $rest = ''; + $value = explode(' ',$value); + if (count($value) - 1) + { + $rest = $value; + $value = $value[0]; + unset($rest[0]); + $rest = implode($rest,' '); + } else + { + $value = explode("\t",$value[0]); + if (count($value) - 1) + { + $rest = $value; + $value = $value[0]; + unset($rest[0]); + $rest = implode($rest,"\t"); + } else $value = $value[0]; + } + preg_match("/^([^`~!@#$%^&*(){}|<>,;]+)$/",$value,$match); + if (!isset($match[0])) + { + // if were a single line and the only bad character is a space then will fix things for them + preg_match("/^([^`~!@#$%^&*(){}|<>,;]+)$/",$value,$match); + if (!isset($match[0])) + { + addError(PDERROR_ILLEGAL_PACKAGENAME,'package','package',$value); + $value = $GLOBALS['phpDocumentor_DefaultPackageName']; + } + else + { + $value = + str_replace(array(" ","/","\\",":"),"_", + trim($value)); + } + } + $this->packagedescrip = $this->package = trim($value); + if (!empty($rest)) $this->packagedescrip = $rest; + } else + { + if (is_string($value)) + addError(PDERROR_MULTIPLE_PACKAGE_TAGS,$value); + else + addError(PDERROR_MULTIPLE_PACKAGE_TAGS,$value->getString()); + } + } elseif ($keyword == 'subpackage') + { + if (empty($this->subpackage)) + { + if (!is_string($value)) + $value = $value->getString(); + $rest = ''; + $value = explode(' ',$value); + if (count($value) - 1) + { + $rest = $value; + $value = $value[0]; + unset($rest[0]); + $rest = implode($rest,' '); + } else + { + $value = explode("\t",$value[0]); + if (count($value) - 1) + { + $rest = $value; + $value = $value[0]; + unset($rest[0]); + $rest = implode($rest,"\t"); + } else $value = $value[0]; + } + if (!empty($value)) + { + preg_match("/^([^`~!@#$%^&*(){}|<>,;]+)$/",$value,$match); + if (!isset($match[0])) + { + // if were a single line and the only bad character is a space then will fix things for them + preg_match("/^([^`~!@#$%^&*(){}|<>,;]+)$/",$value,$match); + if (!isset($match[0])) + { + addError(PDERROR_ILLEGAL_PACKAGENAME,'subpackage','subpackage',$value); + $value = ''; + } + else + { + $value = + str_replace(array(" ","/","\\",":"),"_", + trim($value)); + } + } + } + $this->subpackage = trim($value); + if (!empty($rest)) $this->subpackagedescrip = $rest; + } else + { + if (is_string($value)) + addError(PDERROR_MULTIPLE_SUBPACKAGE_TAGS,$value); + else + addError(PDERROR_MULTIPLE_SUBPACKAGE_TAGS,$value->getString()); + } + } elseif ($keyword == 'category') + { + if (!$this->explicitcategory) + { + if (!is_string($value)) + $value = $value->getString(); + $this->category = $value; + } else + { + if (is_string($value)) + addError(PDERROR_MULTIPLE_CATEGORY_TAGS,$value); + else + addError(PDERROR_MULTIPLE_CATEGORY_TAGS,$value->getString()); + } + } + } + + /** + * Adds a @name tag to the tag list + * @param string new name of element + */ + function addName($value) + { + if (is_object($value)) $value = $value->getString(); + if (!$this->hasname) + { + $x = new parserNameTag('name',$value); + $this->hasname = true; + $this->tags['name'][] = $x; + } else + { + addError(PDERROR_MULTIPLE_NAME_TAGS,$value); + } + } + + /** + * @param string if empty, staticvar is indexed in the order received and set using {@link changeStatic()} + * @param string data type + * @param parserStringWithInlineTags + */ + function addStaticVar($staticvar, $type, $descrip) + { + if (empty($staticvar)) + $this->statics[] = new parserStaticvarTag($type,$descrip); + else + $this->statics[$staticvar] = new parserStaticvarTag($type,$descrip); + } + + /** + * adds a function declaration of @global to the {@link $funcglobals} array + * @param string global type + * @param string description of how the global is used in the function + */ + function addFuncGlobal($type,$value) + { + $this->funcglobals[] = array($type,$value); + } + + /** + * @param integer $index index of parameter in the {@link $funcglobals} array + * @param string $name name of the parameter to set in the $funcglobals array + */ + function changeGlobal($index,$name) + { + $this->funcglobals[$name] = $this->funcglobals[$index]; + unset($this->funcglobals[$index]); + } + + /** + * @param integer $index index of parameter in the {@link $statics} array + * @param string $name name of the parameter to set in the $statics array + */ + function changeStatic($index,$name) + { + $this->statics[$name] = $this->statics[$index]; + unset($this->statics[$index]); + } + + /** + * replaces nameless global variables in the {@link $funcglobals} array with their names + * @param array + */ + function updateGlobals($funcs) + { + for($i=0;$ifuncglobals[$i])) + { + $this->changeGlobal($i,$funcs[$i]); + } + } + } + + /** + * replaces nameless static variables in the {@link $statics} array with their names + * @param array + */ + function updateStatics($funcs) + { + for($i=0;$istatics[$i])) + { + $this->changeStatic($i,$funcs[$i]); + } + } + } + + /** + * add an @access tag to the {@link tags} array + * @param string should be either public or private + */ + function addAccess($value) + { + if (is_object($value)) $value = $value->getString(); + $value = strtolower($value); + if (!$this->hasaccess) + { + $x = new parserAccessTag($value); + if ($x->isvalid) + { + $this->hasaccess = true; + $this->tags['access'][] = $x; + } + } else + { + if (is_string($value)) + addError(PDERROR_MULTIPLE_ACCESS_TAGS,$value); + else + addError(PDERROR_MULTIPLE_ACCESS_TAGS,$value->getString()); + } + } + + /** + * Adds a new @filesource tag to the DocBlock + * @tutorial tags.filesource.pkg + * @param string full path to the file + * @param array tokenized source code, ordered by line number + */ + function addFileSource($path, $source) + { + if (isset($this->tags['filesource'])) return; + $this->tags['filesource'][] = new parserFileSourceTag($path, $source); + } + + /** + * creates a {@link parserLinkTag} and adds it to the {@link $tags} array + * @param string $link + */ + function addLink($link) + { + if (phpDocumentor_setup::checkIgnoreTag('@link')) return; + $this->tags['link'][] = new parserLinkTag($link); + } + + /** + * creates a {@link parserLinkTag} and adds it to the {@link $tags} array + * @param string either see or uses + * @param string $value + */ + function addSee($keyword,$value) + { + if (phpDocumentor_setup::checkIgnoreTag($keyword)) return; + $tag = 'parser'.ucfirst($keyword).'Tag'; + $this->tags[$keyword][] = new $tag($value); + } + + /** + * creates a {@link parserReturnTag} and adds it to the {@link $tags} array + * @param string $returnType the one-word name of the return type (mixed should be used if more than one type) + * @param parserStringWithInlineTags $value + */ + function addReturn($returnType, $value) + { + // only take the first one + if (!$this->return) + { + $this->return = new parserReturnTag($returnType, $value); + } else + { + addError(PDERROR_MULTIPLE_RETURN_TAGS,$returnType,$value->getString()); + } + } + + /** + * creates a {@link parserVarTag} and adds it to the {@link $tags} array + * @param string $varType the one-word name of the variable type (mixed should be used if more than one type) + * @param parserStringWithInlineTags $value + */ + function addVar($varType, $value) + { + // only take the first one + if (!$this->var) + { + $this->var = new parserVarTag($varType, $value); + } else + { + addError(PDERROR_MULTIPLE_VAR_TAGS,$varType,$value->getString()); + } + } + + /** + * Adds a virtual @usedby tag to output + * @param abstractLink link to the element that has a @uses tag + * @param parserStringWithInlinetags description of how the elements uses + * this one + * @access private + */ + function addUsedBy($link, $descrip) + { + $this->tags['usedby'][] = new parserUsedByTag($link, $descrip); + } + + /** + * Add a @uses tag to the DocBlock + * @param string @see-style text, used for {@link Converter::getLink()} + * @param parserStringWithInlineTags description of how the used element is + * used + * @tutorial tags.uses.pkg + */ + function addUses($seeel, $description) + { + $this->tags['uses'][] = new parserUsesTag($seeel, $description); + } + + /** + * @param string + * @return mixed false if no keyword, unconverted value if one keyword, array of unconverted values if more than one keyword + */ + function getKeyword($keyword) + { + if ($keyword == 'filesource' && !$this->_canSource) return false; + if (isset($this->tags[$keyword])) + { + if (count($this->tags[$keyword]) == 1) + { + return $this->tags[$keyword][0]; + } else return $this->tags[$keyword]; + } else return false; + } + + /** + * @return array Format: array('var' => tag name, 'data' => unconverted tag value) + */ + function listParams() + { + if (isset($this->params)) + { + $ret = array(); + foreach($this->params as $key => $val) + { + $ret[] = array("var" => ucfirst($key),"data" => $val); + } + return $ret; + } else { + return array(); + } + } + + /** + * @param Converter + */ + function listTags() + { + $tags = array(); + foreach($this->tags as $keyword => $vals) + { + if ($keyword == 'filesource' && !$this->_canSource) continue; + foreach($vals as $val) + { + $tags[] = $val; + } + } + usort($tags,'tagsort'); + return $tags; + } + + /** @return string always 'docblock' */ + function getType() + { + return 'docblock'; + } +} + +/** + * @access private + */ +function tagsort($a, $b) +{ + switch(phpDocumentor_get_class($a)) + { + case 'parsertag' : + switch ($a->keyword) + { + case 'author' : + $o = 3; + break; + case 'version' : + $o = 4; + break; + case 'deprecated' : + case 'deprec' : + $o = 7; + break; + case 'todo' : + case 'TODO' : + $o = 8; + break; + case 'abstract' : + $o = 9; + break; + } + case 'parseraccesstag' : + $o = 10; + break; + case 'parsernametag' : + $o = 11; + break; + case 'parserseetag' : + $o = 5; + break; + case 'parserlinktag' : + $o = 6; + break; + case 'parserreturntag' : + $o = 0; + break; + case 'parservartag' : + $o = 1; + break; + case 'parserstaticvartag' : + $o = 2; + break; + default : + $o = 12; + break; + } + switch(phpDocumentor_get_class($b)) + { + case 'parsertag' : + switch ($b->keyword) + { + case 'author' : + $p = 3; + case 'version' : + $p = 4; + case 'deprecated' : + case 'deprec' : + $p = 7; + case 'todo' : + case 'TODO' : + $p = 8; + case 'abstract' : + $p = 9; + } + case 'parseraccesstag' : + $p = 10; + case 'parsernametag' : + $p = 11; + case 'parserseetag' : + $p = 5; + case 'parserlinktag' : + $p = 6; + case 'parserreturntag' : + $p = 0; + case 'parservartag' : + $p = 1; + case 'parsertutorialtag' : + $p = 1; + case 'parserstaticvartag' : + $p = 2; + default : + $p = 12; + } + if ($o == $p) return 0; + if ($o < $p) return -1; + if ($o > $p) return 1; +} +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/ParserElements.inc b/buildscripts/PhpDocumentor/phpDocumentor/ParserElements.inc new file mode 100644 index 00000000..a95d24b8 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/ParserElements.inc @@ -0,0 +1,1910 @@ + + * @since 1.0rc1 + * @version $Id: ParserElements.inc,v 1.2 2005/11/28 07:27:59 cellog Exp $ + */ +class parserElement extends parserBase +{ + /** + * @var mixed either false or a {@link parserDocBlock} + */ + var $docblock = false; + /** + * name of this element, or include type if element is a {@link parserInclude} + */ + var $name; + + /** + * @var mixed either false or an array of paths to files with conflicts + */ + var $conflicts = false; + + /** + * location of this element (filename) + * @var string + */ + var $file = ''; + + /** + * full path location of this element (filename) + * @var string + */ + var $path = ''; + + /** + * line number on file where this element stops + * @since 1.2 + * @var false|integer + */ + var $endlinenumber = 0; + + /** + * Line number in the source on which this element appears + * @since 1.2 + * @var false|integer + */ + var $linenumber = false; + + /** + * @param parserDocBlock + */ + function setDocBlock($docblock) + { + $this->docblock = $docblock; + } + + /** + * @param string + */ + function setName($name) + { + $this->name = trim($name); + } + + /** + * Set starting line number + * @param integer + */ + function setLineNumber($number) + { + $this->linenumber = $number; + } + + /** + * Sets the ending line number of elements + * @param integer + */ + function setEndLineNumber($l) + { + $this->endlinenumber = $l; + } + + /** + * @return integer + */ + function getLineNumber() + { + return $this->linenumber; + } + + /** + * @return integer + */ + function getEndLineNumber() + { + return $this->endlinenumber; + } + + /** @return string package containing this element */ + function getPackage() + { + if ($this->docblock) + { + return $this->docblock->package; + } else return $GLOBALS['phpDocumentor_DefaultPackageName']; + } + + /** @param string */ + function setFile($file) + { + $this->file = $file; + } + + /** @param string */ + function setPath($file) + { + // look for special windows case + if(SMART_PATH_DELIMITER === '\\') + $this->path = strtr($file,'/','\\'); + else + $this->path = $file; + $this->path = $file; + } + + /** + * @return string + */ + function getName() + { + if (!isset($this->name)) return false; + return $this->name; + } + + /** + * @return string + */ + function getFile() + { + if (!isset($this->file)) return false; + return $this->file; + } + + /** + * @return string + */ + function getPath() + { + if (!isset($this->path)) return false; + return $this->path; + } +} + +/** + * @package phpDocumentor + * @subpackage ParserElements + * @author Greg Beaver + * @since 1.0rc1 + * @version $Id: ParserElements.inc,v 1.2 2005/11/28 07:27:59 cellog Exp $ + */ +class parserInclude extends parserElement +{ + /** + * Type is used by many functions to skip the hassle of if phpDocumentor_get_class($blah) == 'parserBlah' + * @var string always 'include' + */ + var $type = 'include'; +} + +/** + * @package phpDocumentor + * @subpackage ParserElements + * @author Greg Beaver + * @since 1.1 + * @version $Id: ParserElements.inc,v 1.2 2005/11/28 07:27:59 cellog Exp $ + */ +class parserGlobal extends parserElement +{ + /** + * Type is used by many functions to skip the hassle of if phpDocumentor_get_class($blah) == 'parserBlah' + * @var string always 'global' + */ + var $type = 'global'; + + /** + * Name of the global's data type + * @var string + */ + var $datatype = 'mixed'; + + /** + * quick way to link to this element + * @return mixed converter-specific link to this global variable + * @param Converter + * @param string text to display for the link or false for default text + */ + function getLink(&$c, $text = false, $returnobj = false) + { + if ($returnobj) + { + return $c->getLink('global ' . $this->name, $this->docblock->package); + } + return $c->getGlobalLink($this->name, $this->docblock->package, $this->path, $text); + } + + /** + * Returns all global variables in other packages that have the same name as this global variable + * @return mixed false or an array Format: (package => {@link parserGlobal} of conflicting global variable) + * @param Converter + */ + function getConflicts(&$c) + { + $a = $c->proceduralpages->getGlobalConflicts($this->name); + unset($a[$this->docblock->package]); + return $a; + } + + /** + * Sets the name of the global variable's type + * @param string + */ + function setDataType($type) + { + $this->datatype = $type; + } + + /** + * Retrieve converter-specific representation of the data type + * + * If the data type is a documented class name, then this function will + * return a Converter-specific link to that class's documentation, so users + * can click/browse to the documentation directly from the global variable + * declaration + * @return string + * @param Converter + */ + function getDataType(&$converter) + { + $converted_datatype = $this->datatype; + if (strpos($this->datatype,'|')) + { + $types = explode('|',$this->datatype); + foreach($types as $returntype) + { + $a = $converter->getLink($returntype); + if (is_object($a) && phpDocumentor_get_class($a) == 'classlink') + { + if (!empty($my_types)) $my_types .= '|'; + $my_types .= $converter->returnSee($a,$converter->type_adjust($returntype)); + } else + { + if (!empty($my_types)) $my_types .= '|'; + $my_types .= $converter->type_adjust($returntype); + } + } + $converted_datatype = $my_types; + } else + { + $a = $converter->getLink($this->datatype); + if (is_object($a) && phpDocumentor_get_class($a) == 'classlink') + { + $converted_datatype = $converter->returnSee($a,$converter->type_adjust($this->datatype)); + } else + { + $converted_dataype = $converter->type_adjust($this->datatype); + } + } + return $converted_datatype; + } + +} + +/** + * @package phpDocumentor + * @subpackage ParserElements + * @author Greg Beaver + * @since 1.0rc1 + * @version $Id: ParserElements.inc,v 1.2 2005/11/28 07:27:59 cellog Exp $ + */ +class parserFunction extends parserElement +{ + /** + * Type is used by many functions to skip the hassle of if phpDocumentor_get_class($blah) == 'parserBlah' + * @var string always 'function' + */ + var $type = 'function'; + /** + * parameters parsed from function definition. + * + * param name may be null, in which case, updateParams() must be called from the Converter + * @var array Format: array(param name => default value parsed from function definition) + * @see updateParams() + */ + var $params = false; + /** + * Function returns a reference to an element, instead of a value + * + * set to true if function is declared as: + * + * function &func(... + * + * @var boolean + */ + var $returnsreference = false; + /** + * global declarations parsed from function definition + * + * @var array Format: array(globalname1, globalname2,....) + */ + var $globals = false; + /** + * static variable declarations parsed from function definition + * @var array Format: array(array('name' => staticvar1,'val' => '' or default val of staticvar1),...) + */ + var $statics = false; + + var $source = ''; + /** + * @param string + * @param string default value parsed from function definition + * @param boolean indicates whether this parameter has a default value + */ + function addParam($name, $value, $has_default = true) + { + $this->params[$name] = array($value, $has_default); + } + + /** + * Set the source code. Always array in PHP 4.3.0+ + * @param string|array + */ + function addSource($source) + { + $this->source = $source; + } + + /** + * Determine whether the source code has been requested via {@}source} + * @return boolean + */ + function hasSource() + { + if (is_array($this->source)) return true; + return strlen($this->source); + } + + /** + * @return string|array source code ready for highlighting + */ + function getSource() + { + return $this->source; + } + + /** + * quick way to link to this element + * @return mixed converter-specific link to this function + * @param Converter + * @param string text to display for the link or false for default text + */ + function getLink($c, $text = false, $returnobj = false) + { + if ($returnobj) + { + return $c->getLink('function ' . $this->name, $this->docblock->package); + } + return $c->getFunctionLink($this->name, $this->docblock->package, $this->path, $text); + } + + /** + * Returns all functions in other packages that have the same name as this function + * @return mixed false or an array Format: (package => {@link parserFunction} of conflicting functions) + * @param Converter + */ + function getConflicts(&$c) + { + $a = $c->proceduralpages->getFuncConflicts($this->name); + unset($a[$this->docblock->package]); + return $a; + } + + /** + * Add all "global $var, $var2" declarations to this function + * @param array $globals Format: array(globalname1, globalname2,....) + */ + function addGlobals($globals) + { + $this->globals = $globals; + } + + /** + * Add all "static $var, $var2 = 6" declarations to this function + * @param array Format: array(varname1, varname2,...) + * @param array Format: array(default val of var 1, default val of var 2,...) if var 1 has no default, array(default val of var 2,...) + */ + function addStatics($static,$vals) + { + if (count($static)) + { + $this->statics = array(); + for($i=0;$istatics[] = array('name' => $static[$i],'val' => $a); + } + } + } + } + + /** + * @return string default value of param $name + * @param string + */ + function getParam ($name) + { + if (!isset($this->params[$name])) return false; + $test = $this->params[$name]; + if ($test[1]) + { + return $this->params[$name]; + } else + { + return false; + } + } + + /** + * @return array format: array(array(paramname, default value),...) + */ + function listParams () + { + if (isset($this->params)) + { + $ret = array(); + if ($this->params) + foreach($this->params as $key => $val) + { + if ($val[1]) + { + $arr = array($key,$val[0]); + if (isset($val[2])) + { + $arr[2] = $val[2]; + } + $ret[] = $arr; + } else + { + $arr = array($key,false); + if (isset($val[2])) + { + $arr[2] = $val[2]; + } + $ret[] = $arr; + } + } + return $ret; + } else { + return array(); + } + } + + /** + * @return array format: array(array(index, globalname),...) + */ + function listGlobals () + { + if (isset($this->globals)) + { + $ret = array(); + if ($this->globals) + foreach($this->globals as $key => $val) + { + $ret[] = array($key,$val); + } + return $ret; + } else { + return array(); + } + } + + /** + * @return array format: array(array(static var name, static var default value),...) + */ + function listStatics () + { + if (isset($this->statics)) + { + $ret = array(); + if ($this->statics) + foreach($this->statics as $key => $val) + { + $ret[] = array($val['name'],$val['val']); + } + return $ret; + } else { + return array(); + } + } + + /** + * sets {@link $returnsreference} to true + */ + function setReturnsReference() + { + $this->returnsreference = true; + } + + /** + * @return boolean returns value of {@link $returnsreference} + */ + function getReturnsReference() + { + return $this->returnsreference; + } + + /** + * Get a human-friendly description of the function call + * + * takes declaration like: + * + * /** @returns string ... {rest of docblock} + * function &func($param1, $param2 = 6, + * $param3 = array('20',9 => "heroo")) + * {...} + * + * and returns: + * string &func( $param1, [$param2 = 6], [$param3 = array('20',9 => "heroo")] ) + * @return string stylized function declaration + */ + function getFunctionCall() + { + $a = ''; + if ($this->getReturnsReference()) $a = '&'; + $function_call = $a.$this->getName() . " ( "; + $tmp = 0; + foreach($this->listParams() as $param) + { + if ($tmp == 0) + { + $tmp = 1; + } else { + $function_call .= ", "; + } + if ($param[1] !== false) + { + $function_call .= "[$param[0] = $param[1]]"; + } else { + $function_call .= $param[0]; + } + $update_params[] = $param[0]; + } + $function_call .= " )"; + return $function_call; + } + + /** + * Like getFunctionCall(), but has no English or pre-determined formatting. + * + * Much more flexible. + * @return array Format: + * + * array('name' => function name, + * 'returnsref' => boolean if declared as "function &name()" + * 'params' => array('type' => data type of parameter, + * 'description' => from @param tag, + * 'name' => variable name, + * 'default' => default value if any)) + * + * @see getFunctionCall() + */ + function getIntricateFunctionCall($converter,$paramtags) + { + $a = array(); + if ($this->getReturnsReference()) $a['returnsref'] = true; + $a['name'] = $converter->type_adjust($this->getName()); + $c = $this->listParams(); + foreach($c as $param) + { + $b = array(); + $b['type'] = 'mixed'; + if (isset($paramtags[$param[0]])) + { + $b['type'] = $paramtags[$param[0]]['datatype']; + $b['description'] = $paramtags[$param[0]]['data']; + unset($paramtags[$param[0]]); + } elseif(isset($paramtags[substr($param[0],1)])) + { + $b['type'] = $paramtags[substr($param[0],1)]['datatype']; + $b['description'] = $paramtags[substr($param[0],1)]['data']; + unset($paramtags[substr($param[0],1)]); + } + if (isset($param[2])) + { + $b['type'] = $param[2]; + } + $b['name'] = $param[0]; + $b['default'] = $param[1]; + $b['hasdefault'] = ($param[1] !== false); + $a['params'][] = $b; + } + // @param tags that don't correspond to actual parameters (like extra function values) + if (count($paramtags)) + { + foreach($paramtags as $param) + { + $b = array(); + $b['type'] = $param['datatype']; + $b['description'] = $param['data']; + $b['name'] = $param['var']; + $b['default'] = ''; + $b['hasdefault'] = false; + $a['params'][] = $b; + } + } + return $a; + } +} + +/** + * @package phpDocumentor + * @subpackage ParserElements + * @author Greg Beaver + * @since 1.0rc1 + * @version $Id: ParserElements.inc,v 1.2 2005/11/28 07:27:59 cellog Exp $ + */ +class parserClass extends parserElement +{ + /** + * Type is used by many functions to skip the hassle of if phpDocumentor_get_class($blah) == 'parserBlah' + * @var string always 'class' + */ + var $type = 'class'; + /** @var string + * @see parserPage::$sourceLocation */ + var $sourceLocation = ''; + /** + * @var mixed false or contents of extends clause in class declaration + */ + var $extends = false; + /** + * @var array a list of interfaces this class implements + */ + var $_implements = array(); + /** + * @var array a list of interfaces this class implements + * @access private + */ + var $_modifiers = false; + /** + * @var boolean determines whether a class is considered to be an interface + * @access private + */ + var $_isInterface = false; + /** + * Format: array(file, parent) where parent class is found or false if no parent + * @var mixed + */ + var $parent = false; + /** + * Used to determine whether a class should be ignored or not. Helps maintain integrity of parsing + * @var boolean + * @see Classes::getParentClass() + */ + var $ignore = false; + + /** + * @var string same as {@link parserElement::$path} + */ + var $curfile = false; + /** + * @var tutorialLink|false either a link to the tutorial associated with this class, or false + */ + var $tutorial = false; + + /** + * Return name of the class that contains this method + * @return string + */ + function getModifiers() + { + return $this->_modifiers; + } + + /** + * Return name of the class that contains this method + * @return string + */ + function setModifiers($m) + { + $this->_modifiers = $m; + } + + /** + * @param parserTutorial + * @param Converter + */ + function addTutorial($t,&$c) + { + $this->tutorial = new tutorialLink; + $this->tutorial->addLink('',$t->path,$t->name,$t->package,$t->subpackage,$t->getTitle($c)); + } + + /** + * Get the associated tutorial for this class, if any + * @tutorial tutorials.pkg + * @return parserTutorial + */ + function getTutorial() + { + return $this->tutorial; + } + + /** + * Returns all classes in other packages that have the same name as this class + * @return mixed false or an array Format: (package => {@link parserClass} of conflicting classes) + * @param Converter + */ + function getConflicts(&$c) + { + $a = $c->classes->getConflicts($this->name); + unset($a[$this->docblock->package]); + return $a; + } + + /** + * quick way to link to this element + * @return mixed converter-specific link to this class + * @param Converter + * @param string text to display for the link or false for default text + */ + function getLink($c, $text = false, $returnobj = false) + { + if ($returnobj) + { + return $c->getLink('object ' . $this->name, $this->docblock->package); + } + return $c->getClassLink($this->name, $this->docblock->package, $this->curfile, $text); + } + + /** + * @param string parent class name + * @param string parent class file + * @param Classes {@link Classes} object currently calling setParent + * @see Classes::setClassParent() + */ + + function setParent($p,$f, &$c) + { + $this->parent = array($f, $p); + $p = $c->getClass($p, $f); + // inherit package if no @package tag is in the docblock, fixes 591396 + if (!$this->docblock->getExplicitPackage()) + { + $this->docblock->package = $p->docblock->package; + } + if ($this->docblock->package == $p->docblock->package) + { + if ($this->docblock->subpackage == '') + $this->docblock->subpackage = $p->docblock->subpackage; + } + $author = $p->docblock->getKeyword('author'); + $version = $p->docblock->getKeyword('version'); + $copyright = $p->docblock->getKeyword('copyright'); + // inherit tags + if (!$this->docblock->getKeyword('author')) + { + if ($author && !is_array($author)) $author = array($author); + if ($author) $this->docblock->tags['author'] = $author; + } + if (!$this->docblock->getKeyword('version')) + { + if ($version && !is_array($version)) $version = array($version); + if ($version) $this->docblock->tags['version'] = $version; + } + if (!$this->docblock->getKeyword('copyright')) + { + if ($copyright && !is_array($copyright)) $copyright = array($copyright); + if ($copyright) $this->docblock->tags['copyright'] = $copyright; + } + if (!$this->docblock->sdesc) + { + $this->docblock->setShortDesc($p->docblock); + $this->docblock->setDesc($p->docblock); + } else + { + if ($this->docblock->hasInheritDoc()) + { + $this->docblock->replaceInheritDoc($p->docblock); + } + } + } + + /** + * @param string $par parent class name (used by {@link Classes::setClassParent()} if parent class not found + */ + function setParentNoClass($par) + { + $this->parent = $par; + } + + /** + * Use this method to set the type of class to be an interface + */ + function setInterface() + { + $this->_isInterface = true; + } + + /** + * @return boolean true if this is an interface class + */ + function isInterface() + { + return $this->_isInterface; + } + + /** + * Use this method to set access modifiers for a class + * @param array + */ + function setAccessModifiers($modifiers) + { + $this->_modifiers = $modifiers; + } + + /** + * retrieve object that represents the parent class + * @param Converter this function will not work before the Conversion stage of parsing + * @return mixed returns the {@link parserClass} representation of the parent class, or false if no parent class + */ + function &getParent(&$c) + { + $a = false; + if (!$this->parent) return $a; + if (is_array($this->parent)) + { + return $c->classes->getClass($this->parent[1],$this->parent[0]); + } else return $this->parent; + } + + /** + * @param Converter this function will not work before the Conversion stage of parsing + * @return array returns a simple array of method objects + */ + function getMethods(&$c) + { + return $c->classes->getMethods($this->name,$this->curfile); + } + + /** + * @return mixed {@link parserMethod} or false if not found + * @param Converter this function will not work before the Conversion stage of parsing + * @param string method name in this class + */ + function getMethod(&$c, $name) + { + return $c->classes->getMethod($this->name,$this->curfile,$name); + } + + /** + * @return mixed {@link parserVar} or false if not found + * @param Converter this function will not work before the Conversion stage of parsing + * @param string var name in this class + */ + function getVar(&$c, $name) + { + return $c->classes->getVar($this->name,$this->curfile,$name); + } + + /** + * @param Converter this function will not work before the Conversion stage of parsing + * @return array returns a simple array of method name strings + */ + function getMethodNames(&$c) + { + if (!$c->classes->hasMethods($this->curfile, $this->name)) return array(); + $arr = array(); + $arr1 = $this->getMethods($c); + for($i=0; $i < count($arr1); $i++) + { + $arr[] = $arr1[$i]->name; + } + return $arr; + } + + /** + * @param Converter this function will not work before the Conversion stage of parsing + * @param string method name + * @return boolean whether this class has a method of name $name + */ + function hasMethod(&$c,$name) + { + return $c->classes->hasMethod($this->name, $this->curfile, $name); + } + + /** + * @param Converter this function will not work before the Conversion stage of parsing + * @param string var name + * @return boolean whether this class has a var of name $name + */ + function hasVar(&$c,$name) + { + return $c->classes->hasVar($this->name, $this->curfile, $name); + } + + /** + * @param Converter this function will not work before the Conversion stage of parsing + * @param string class constant name + * @return boolean whether this class has a constant of name $name + */ + function hasConst(&$c,$name) + { + return $c->classes->hasConst($this->name, $this->curfile, $name); + } + + /** + * @param Converter this function will not work before the Conversion stage of parsing + * @return array returns a simple array of var objects + */ + function getVars(&$c) + { + return $c->classes->getVars($this->name,$this->curfile); + } + + /** + * @param Converter this function will not work before the Conversion stage of parsing + * @return array returns a simple array of const objects + */ + function getConsts(&$c) + { + return $c->classes->getConsts($this->name,$this->curfile); + } + + /** + * @param Converter this function will not work before the Conversion stage of parsing + * @return array returns a simple array of var name strings + */ + function getVarNames(&$c) + { + if (!$c->classes->hasVars($this->curfile, $this->name)) return array(); + $arr = array(); + $arr1 = $this->getVars($c); + for($i=0; $i < count($arr1); $i++) + { + $arr[] = $arr1[$i]->name; + } + return $arr; + } + + /** + * @param Converter this function will not work before the Conversion stage of parsing + * @return array returns a simple array of const name strings + */ + function getConstNames(&$c) + { + if (!$c->classes->hasConsts($this->curfile, $this->name)) return array(); + $arr = array(); + $arr1 = $this->getConsts($c); + for($i=0; $i < count($arr1); $i++) + { + $arr[] = $arr1[$i]->name; + } + return $arr; + } + + /** + * @param Converter this function will not work before the Conversion stage of parsing + * @param boolean determines whether overriden methods should be included in the list of inherited methods + * @return array returns an array of methods by parent classname array(name => array(method1,method2..),name2 => array(method1....)) + */ + function getInheritedMethods(&$c,$override = false) + { + $x = $this; + $methods = array(); + $arr = array(); + while ($x->parent && is_array($x->parent)) + { + $methods = array_merge($methods,$x->getMethodNames($c)); + $par = $x->getParent($c); + $parmethodnames = $par->getMethodNames($c); + $parmethods = $par->getMethods($c); + for($i=0; $idocblock && $parmethods[$i]->docblock->hasaccess && !$c->parseprivate && $parmethods[$i]->docblock->tags['access'][0]->value == 'private') + { + continue; + } + $methods[] = $parmethodnames[$i]; + $arr[$par->getName()]['methods'][] = $parmethods[$i]; + $arr[$par->getName()]['file'] = $par->curfile; + } + } else + { + // fix for bug 587733 + if ($parmethods[$i]->docblock && $parmethods[$i]->docblock->hasaccess && !$c->parseprivate && $parmethods[$i]->docblock->tags['access'][0]->value == 'private') + { + continue; + } + $arr[$par->getName()]['methods'][] = $parmethods[$i]; + $arr[$par->getName()]['file'] = $par->curfile; + } + } + $x = &$par; + } + return $arr; + } + + /** + * @param Converter this function will not work before the Conversion stage of parsing + * @param boolean determines whether overriden vars should be included in the list of inherited vars + * @return array returns an array of vars by parent classname array(name => array(var1,var1..),name2 => array(var1....)) + */ + function getInheritedVars(&$c,$override = true, $vars = false) + { + $x = $this; + $vars = array(); + $arr = array(); + while ($x->parent && is_array($x->parent)) + { + $vars = array_merge($vars,$x->getVarNames($c)); + $par = $x->getParent($c); + $parvarnames = $par->getVarNames($c); + $parvars = $par->getVars($c); + for($i=0; $idocblock && $parvars[$i]->docblock->hasaccess && !$c->parseprivate && $parvars[$i]->docblock->tags['access'][0]->value == 'private') + { + continue; + } + $vars[] = $parvarnames[$i]; + $arr[$par->getName()]['vars'][] = $parvars[$i]; + $arr[$par->getName()]['file'] = $par->curfile; + } + } else + { + // fix for bug 587733 + if ($parvars[$i]->docblock && $parvars[$i]->docblock->hasaccess && !$c->parseprivate && $parvars[$i]->docblock->tags['access'][0]->value == 'private') + { + continue; + } + $arr[$par->getName()]['vars'][] = $parvars[$i]; + $arr[$par->getName()]['file'] = $par->curfile; + } + } + $x = &$par; + } + return $arr; + } + + /** + * @param Converter this function will not work before the Conversion stage of parsing + * @param boolean determines whether overriden vars should be included in the list of inherited vars + * @return array returns an array of consts by parent classname array(name => array(const1,const2..),name2 => array(const1....)) + */ + function getInheritedConsts(&$c,$override = false, $consts = false) + { + $x = $this; + $consts = array(); + $arr = array(); + while ($x->parent && is_array($x->parent)) + { + $consts = array_merge($consts,$x->getConstNames($c)); + $par = $x->getParent($c); + $parvarnames = $par->getConstNames($c); + $parvars = $par->getConsts($c); + for($i=0; $idocblock && $parvars[$i]->docblock->hasaccess && !$c->parseprivate && $parvars[$i]->docblock->tags['access'][0]->value == 'private') + { + continue; + } + $consts[] = $parvarnames[$i]; + $arr[$par->getName()]['consts'][] = $parvars[$i]; + $arr[$par->getName()]['file'] = $par->curfile; + } + } else + { + // fix for bug 587733 + if ($parvars[$i]->docblock && $parvars[$i]->docblock->hasaccess && !$c->parseprivate && $parvars[$i]->docblock->tags['access'][0]->value == 'private') + { + continue; + } + $arr[$par->getName()]['consts'][] = $parvars[$i]; + $arr[$par->getName()]['file'] = $par->curfile; + } + } + $x = &$par; + } + return $arr; + } + + /** + * @param Converter this function will not work before the Conversion stage of parsing + * @return array Format: array(parentclassname => parserClass/false if no parent, parentclassname2 => ...) + */ + function getParentClassTree(&$c) + { + $result = array(); + $result[$this->name] = $arr = $this->getParent($c); + if (is_string($arr)) $result[$arr] = false; + while ($arr && is_object($arr)) + { + $result[$arr->name] = $arr->getParent($c); + $arr = $arr->getParent($c); + if (is_string($arr)) $result[$arr] = false; + } + return $result; + } + + /** + * returns a list of all child classes of this class + * @param Converter this function will not work before the Conversion stage of parsing + * @return array Format: array(parserClass child1,parserClass child2,...) + */ + function getChildClassList(&$c) + { + $list = array(); + $kids = $c->classes->getDefiniteChildren($this->name,$this->curfile); + if ($kids) + { + foreach($kids as $chile => $file) + { + $list[] = $c->classes->getClass($chile,$file); + } + } + return $list; + } + + /** + * @param string + * @see $sourceLocation + */ + function setSourceLocation($sl) + { + $this->sourceLocation = $sl; + } + + /** + * @param Converter + * @param boolean + * @return string + * @see $sourceLocation + */ + function getSourceLocation($c,$pearize = false) + { + global $_phpDocumentor_options; + if (!isset($this->sourceLocation)) return false; + if ($pearize) + { + $sl = $this->sourceLocation; + if (strpos($sl,'pear/')) + { + $sl = substr($sl,strpos($sl,'pear/') + 5); + return $sl; + } else + { + return $sl; + } + return $sl; + } + return $this->sourceLocation; + } + + /** + * @param string + * @see $extends + */ + function setExtends($extends) + { + $this->extends = $extends; + } + + /** + * @param string + */ + function addImplements($implements) + { + $this->_implements[] = $implements; + } + + /** + * @return array + */ + function getImplements() + { + return $this->_implements; + } + + /** + * @return boolean + * @see $extends + */ + function getExtends() + { + if (!isset($this->extends)) return false; + return $this->extends; + } +} + +/** + * @package phpDocumentor + * @subpackage ParserElements + * @author Greg Beaver + * @since 1.0rc1 + * @version $Id: ParserElements.inc,v 1.2 2005/11/28 07:27:59 cellog Exp $ + */ +class parserVar extends parserElement +{ + /** + * Type is used by many functions to skip the hassle of if phpDocumentor_get_class($blah) == 'parserBlah' + * @var string always 'var' + */ + var $type = 'var'; + /** @var string class that contains this var */ + var $class = ''; + /** @var array */ + var $_modifiers; + + /** + * @param string + */ + function parserVar($class) + { + $this->class = $class; + } + + /** + * Retrieve the class name + * @return string Class name that this var belongs to + */ + function getClass() + { + return $this->class; + } + + /** + * Return name of the class that contains this method + * @return string + */ + function getModifiers() + { + return $this->_modifiers; + } + + /** + * Return name of the class that contains this method + * @return string + */ + function setModifiers($m) + { + $this->_modifiers = $m; + } + + /** + * quick way to link to this element + * @return mixed converter-specific link to this var + * @param Converter $c + * @param string $text text to display for the link or false for default text + */ + function getLink($c, $text = false, $returnobj = false) + { + if ($returnobj) + { + return $c->getLink($this->class . '::' . $this->name, $this->docblock->package); + } + return $c->getVarLink($this->name, $this->class, $this->docblock->package, false, $text); + } + + /** + * @param Converter + * @return mixed {@link parserVar} representing var this var overrides from the parent class, or false if none + */ + function getOverrides(&$c) + { + $class = $c->classes->getClass($this->class,$this->path); + $par = $class->getParent($c); + + while (is_object($par)) + { + if ($par->hasVar($c,$this->name)) + { + $var = $par->getVar($c,$this->name); + if (!($var->docblock && $var->docblock->hasaccess && !$c->parseprivate && $var->docblock->tags['access'][0]->value == 'private')) + return $var; + } + $par = $par->getParent($c); + } + + return false; + } + + /** + * @param Converter + * @return array an array of parserVars from ALL child classes that override this var + */ + function getOverridingVars(&$c) + { + $class = $c->classes->getClass($this->class,$this->path); + + return $this->getOverridingVarsForClass($c, $class); + } + + /** + * @param Converter + * @param parserClass + * @return array an array of parserVars from ALL child classes that override this var in the given class + */ + function getOverridingVarsForClass(&$c, &$class) + { + $vars = array(); + if (!$class) return $meths; + $kids = $class->getChildClassList($c); + for($i=0; $ihasVar($c, $this->name)) + { + $var = $kids[$i]->getVar($c,$this->name); + if (!($var->docblock && $var->docblock->hasaccess && !$c->parseprivate && $var->docblock->tags['access'][0]->value == 'private')) + $vars[] = $var; + } + + $vars = array_merge($vars, $this->getOverridingVarsForClass($c, $kids[$i])); + } + return $vars; + } +} + +/** + * @package phpDocumentor + * @subpackage ParserElements + * @author Greg Beaver + * @since 1.2.4 + */ +class parserConst extends parserElement +{ + /** + * Type is used by many functions to skip the hassle of if phpDocumentor_get_class($blah) == 'parserBlah' + * @var string always 'const' + */ + var $type = 'const'; + /** @var string class that contains this var */ + var $class = ''; + + /** + * @param string + */ + function parserConst($class) + { + $this->class = $class; + } + + /** + * Retrieve the class name + * @return string Class name that this var belongs to + */ + function getClass() + { + return $this->class; + } + + /** + * quick way to link to this element + * @return mixed converter-specific link to this var + * @param Converter $c + * @param string $text text to display for the link or false for default text + */ + function getLink($c, $text = false, $returnobj = false) + { + if ($returnobj) + { + return $c->getLink($this->class . '::'. $this->name, $this->docblock->package); + } + return $c->getConstLink($this->name, $this->class, $this->docblock->package, false, $text); + } +} + +/** + * @package phpDocumentor + * @subpackage ParserElements + * @author Greg Beaver + * @since 1.0rc1 + * @version $Id: ParserElements.inc,v 1.2 2005/11/28 07:27:59 cellog Exp $ + */ +class parserMethod extends parserFunction +{ + /** + * Type is used by many functions to skip the hassle of if phpDocumentor_get_class($blah) == 'parserBlah' + * @var string always 'method' + */ + var $type = 'method'; + /** @var boolean whether this method is a constructor */ + var $isConstructor = false; + /** @var boolean whether this method is a destructor by PEAR standards */ + var $isDestructor = false; + /** @var string class that contains this method */ + var $class = ''; + var $_modifiers = array(); + + /** + * @param string + */ + function parserMethod($class) + { + $this->class = $class; + } + + /** + * @param string + * @param string default value parsed from function definition + * @param boolean indicates whether this parameter has a default value + * @param null|string class type hint + */ + function addParam($name, $value, $has_default = true, $typehint = null) + { + $this->params[$name] = array($value, $has_default); + if (isset($typehint)) + { + $this->params[$name][2] = $typehint; + } + } + + /** + * adds "constructor " to start of function call if {@link $isConstructor} is true + * @return string + * @see parent::getFunctionCall() + */ + function getFunctionCall() + { + $a = parserFunction::getFunctionCall(); + if ($this->isConstructor) $a = "constructor $a"; + return $a; + } + + function getIntricateFunctionCall($converter,$paramtags) + { + $a = parserFunction::getIntricateFunctionCall($converter,$paramtags); + if ($this->isConstructor) $a['constructor'] = true; + if ($this->isDestructor) $a['destructor'] = true; + return $a; + } + + /** + * Return name of the class that contains this method + * @return string + */ + function getClass() + { + return $this->class; + } + + /** + * Return name of the class that contains this method + * @return string + */ + function getModifiers() + { + return $this->_modifiers; + } + + /** + * Return name of the class that contains this method + * @return string + */ + function setModifiers($m) + { + $this->_modifiers = $m; + } + + /** + * @param Converter + * @return mixed {@link parserMethod} representing method this method overrides from the parent class, or false if none + */ + function getOverrides(&$c) + { + $class = $c->classes->getClass($this->class,$this->path); + + $par = $class->getParent($c); + + while (is_object($par)) + { + if ($par->hasMethod($c,$this->name)) + { + $meth = $par->getMethod($c,$this->name); + if (!($meth->docblock && $meth->docblock->hasaccess && !$c->parseprivate && $meth->docblock->tags['access'][0]->value == 'private')) + return $meth; + } + + $par = $par->getParent($c); + } + + return false; + } + + /** + * quick way to link to this element + * @return mixed converter-specific link to this method + * @param Converter $c + * @param string $text text to display for the link or false for default text + */ + function getLink($c, $text = false, $returnobj = false) + { + if ($returnobj) + { + return $c->getLink($this->class . '::' . $this->name . '()', $this->docblock->package); + } + return $c->getMethodLink($this->name, $this->class, $this->docblock->package, false, $text); + } + + /** + * Use this method to tell the parser that this method is the class constructor + */ + function setConstructor() + { + $this->isConstructor = true; + } + + /** + * Use this method to tell the parser that this method is the class constructor + */ + function setDestructor() + { + $this->isDestructor = true; + } + + /** + * @param Converter + * @return array an array of parserMethods from child classes that override this method + */ + function getOverridingMethods(&$c) + { + $class = $c->classes->getClass($this->class,$this->path); + + return $this->getOverridingMethodsForClass($c, $class); + } + + /** + * @param Converter + * @param parserClass + * @return array an array of parserMethods from ALL child classes that override this method in the given class + */ + function getOverridingMethodsForClass(&$c, &$class) + { + $meths = array(); + if (!$class) return $meths; + $kids = $class->getChildClassList($c); + for($i=0; $ihasMethod($c, $this->name)) + { + $meth = $kids[$i]->getMethod($c,$this->name); + if (!($meth->docblock && $meth->docblock->hasaccess && !$c->parseprivate && $meth->docblock->tags['access'][0]->value == 'private')) + $meths[] = $meth; + } + + $meths = array_merge($meths, $this->getOverridingMethodsForClass($c, $kids[$i])); + } + return $meths; + } +} + +/** + * @package phpDocumentor + * @subpackage ParserElements + * @author Greg Beaver + * @since 1.0rc1 + * @version $Id: ParserElements.inc,v 1.2 2005/11/28 07:27:59 cellog Exp $ + */ +class parserDefine extends parserElement +{ + /** + * Type is used by many functions to skip the hassle of if phpDocumentor_get_class($blah) == 'parserBlah' + * @var string always 'define' + */ + var $type = 'define'; + + /** + * quick way to link to this element + * @return mixed converter-specific link to this define + * @param Converter $c + * @param string $text text to display for the link or false for default text + */ + function getLink($c, $text = false, $returnobj = false) + { + if ($returnobj) + { + return $c->getLink('constant ' . $this->name, $this->docblock->package); + } + return $c->getDefineLink($this->name, $this->docblock->package, false, $text); + } + + /** + * Returns all defines in other packages that have the same name as this define + * @return mixed false or an array Format: (package => {@link parserDefine} of conflicting defines) + * @param Converter + */ + function getConflicts(&$c) + { + $a = $c->proceduralpages->getDefineConflicts($this->name); + unset($a[$this->docblock->package]); + return $a; + } + +} + +/** + * @package phpDocumentor + * @subpackage ParserElements + * @author Greg Beaver + * @since 1.0rc1 + * @version $Id: ParserElements.inc,v 1.2 2005/11/28 07:27:59 cellog Exp $ + */ +class parserPackagePage extends parserStringWithInlineTags +{ + /** + * Type is used by many functions to skip the hassle of if phpDocumentor_get_class($blah) == 'parserBlah' + * @var string always 'packagepage' + */ + var $type = 'packagepage'; + /** @var string */ + var $package = 'default'; + + /** + * @param string + */ + function parserPackagePage($package) + { + $this->package = $package; + } + + /** + * @param Converter + */ + function Convert(&$c) + { + return parent::Convert($c,false); + } +} + +/** + * @package phpDocumentor + * @subpackage ParserElements + * @since 1.2 + */ +class parserTutorial extends parserPackagePage +{ + /** + * Type is used by many functions to skip the hassle of if phpDocumentor_get_class($blah) == 'parserBlah' + * @var string always 'tutorial' + */ + var $type = 'tutorial'; + /** @var string */ + var $package = 'default'; + /** + * Either cls, pkg, or proc + * @var string + */ + var $tutorial_type; + /** + * The documentable element this tutorial is linked to + * + * Can be a parserData, parserClass, or nothing for package/subpackage docs + */ + var $linked_element; + /** + * path to the tutorial page + * @var string + */ + var $path; + /** + * filename minus extension of this tutorial (used for @tutorial tag) + * @var string + */ + var $name; + /** @var boolean */ + var $_xml = true; + /** + * output from tutorialname.ext.ini + * + * an array generated by {@link phpDocumentor_parse_ini_file()} containing + * an index 'Linked Tutorials' with an array of tutorial names in the order + * they should appear. This is used to generate a linked list of tutorials like + * {@tutorial phpDocumentor/tags.pkg} + * @var array + */ + var $ini = false; + /** + * link to the next tutorial in a document series, or false if none + * @var tutorialLink + */ + var $next = false; + /** + * link to the previous tutorial in a document series, or false if none + * @var tutorialLink + */ + var $prev = false; + /** + * link to the parent tutorial in a document series, or false if none + * + * This is used to generate an "Up" or "Home" link like the php manual. + * The parent is defined as a tutorial that has a parenttutorialname.ext.ini + * file and is not contained by any other tutorial's tutorialname.ext.ini + * @var tutorialLink + */ + var $parent = false; + /** + * links to the child tutorials, or false if none + * @var array + */ + var $children = false; + + /** + * @param parserXMLDocBookTag top-level tag ( for 1.2.0) + * @param information about the tutorial file. Format: + * + *
                                                    +     * array('tutename' => tutorial name,
                                                    +     *       'path' => relative path of tutorial to tutorials/ directory
                                                    +     *       'ini' => contents of the tutorial .ini file, if any)
                                                    +     * 
                                                    + */ + function parserTutorial($data, $info) + { + $this->value = $data; + $this->package = $info['package']; + $this->subpackage = $info['subpackage']; + $this->tutorial_type = $info['tutetype']; + $this->name = $info['tutename']; + $this->path = $info['path']; + $this->ini = $info['ini']; + } + + /** + * Retrieve the title of the tutorial, or of any subsection + * @param Converter + * @param string which subsection to retrieve the title from, if any + * @uses parserXMLDocBookTag::getSubSection() retrieve the subsection to + * to get a title from + */ + function getTitle(&$c,$subsection = '') + { + if (!empty($subsection)) + { + $z = $this->value->getSubSection($c,$subsection); + if (!$z) + { + addWarning(PDERROR_TUTORIAL_SUBSECTION_NOT_FOUND,$this->name,$subsection); + return $subsection; + } + return $z->getTitle($c); + } + return $this->value->getTitle($c); + } + + /** + * @param Converter + * @param boolean determines whether character data is postprocessed to be + * Converter-friendly or not. + */ + function Convert(&$c, $postprocess = true) + { + return $this->value->Convert($c, $postprocess); + } + + /** + * @uses $parent creates a link to the documentation for the parent tutorial + * @param parserTutorial + * @param Converter + */ + function setParent($parent,&$c) + { + $this->parent = new tutorialLink; + $this->parent->addLink('', $parent->path, $parent->name, $parent->package, $parent->subpackage, $parent->getTitle($c)); + } + + /** + * @param array array of parserTutorials that have child tutorials + */ + function isChildOf($parents) + { + foreach($parents as $i => $parent) + { + if ($parent->path == $this->path) continue; + if ($parent->ini && ($parent->package == $this->package) && ($parent->subpackage == $this->subpackage) && ($parent->tutorial_type == $this->tutorial_type)) + { + foreach($parent->ini['Linked Tutorials'] as $child) + { + if ($child . '.' . $this->tutorial_type == $this->name) return true; + } + } + } + } + + /** + * Retrieve converter-specific link to the parent tutorial's documentation + * @param Converter + */ + function getParent(&$c) + { + if (!$this->parent) return false; + return $c->returnSee($this->parent); + } + + /** + * @uses $next creates a link to the documentation for the next tutorial + * @param parserTutorial + * @param Converter + */ + function setNext($next,&$c) + { + if (phpDocumentor_get_class($next) == 'tutoriallink') return $this->next = $next; + $this->next = new tutorialLink; + $this->next->addLink('', $next->path, $next->name, $next->package, $next->subpackage, $next->getTitle($c)); + } + + /** + * Retrieve converter-specific link to the next tutorial's documentation + * @param Converter + */ + function getNext(&$c) + { + if (!$this->next) return false; + return $c->returnSee($this->next); + } + + /** + * @uses $prev creates a link to the documentation for the previous tutorial + * @param parserTutorial + * @param Converter + */ + function setPrev($prev,&$c) + { + if (phpDocumentor_get_class($prev) == 'tutoriallink') return $this->prev = $prev; + $this->prev = new tutorialLink; + $this->prev->addLink('', $prev->path, $prev->name, $prev->package, $prev->subpackage, $prev->getTitle($c)); + } + + /** + * Retrieve converter-specific link to the previous tutorial's documentation + * @param Converter + */ + function getPrev(&$c) + { + if (!$this->prev) return false; + return $c->returnSee($this->prev); + } + + /** + * Get a link to this tutorial, or to any subsection of this tutorial + * @param Converter + * @param boolean if true, returns a {@link tutorialLink} instead of a string + * @param string section name to link to + * @return string|tutorialLink + */ + function getLink(&$c,$pure = false,$section = '') + { + $link = new tutorialLink; + $link->addLink($section, $this->path, $this->name, $this->package, $this->subpackage, $this->getTitle($c), $this->category); + if ($pure) return $link; + return $c->returnSee($link); + } +} + +?> \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/ProceduralPages.inc b/buildscripts/PhpDocumentor/phpDocumentor/ProceduralPages.inc new file mode 100644 index 00000000..a26fbacc --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/ProceduralPages.inc @@ -0,0 +1,782 @@ + + * @since 1.1 + * @version $Id: ProceduralPages.inc,v 1.1 2005/10/17 18:36:57 jeichorn Exp $ + */ +/** + * Intermediate procedural page parsing structure. + * This structure parses defines, functions, and global variables by file, + * and then iterates over the elements to document conflicts. + * @package phpDocumentor + * @author Greg Beaver + * @since 1.1 + * @version $Id: ProceduralPages.inc,v 1.1 2005/10/17 18:36:57 jeichorn Exp $ + */ +class ProceduralPages +{ + /** + * file being parsed, used in every add function to match up elements with the file that contains them + * @see addClass(), addMethod(), addVar(), nextFile() + * @var string + */ + var $curfile; + /** + * array of all procedural pages ordered by name + * Format: + * array(name => array(fullpath => parserPage,fullpath => parserPage2 [if there are name conflicts],...)) + * @var array + */ + var $pages = array(); + /** + * array of all procedural pages ordered by name that have been ignored via -po or @access private or @ignore + * Format: + * array(name => array(fullpath => parserPage,fullpath => parserPage2 [if there are name conflicts],...)) + * @var array + */ + var $ignorepages = array(); + /** + * array of all procedural page names ordered by full path to the file + * Format: + * array(fullpath => name) + * @var array + */ + var $pathpages = array(); + /** + * array of parsed includes organized by the full path of the file that contains the include. + * Format: + * array(full path => array(includename => {@link parserInclude})) + * @var array + */ + var $includesbyfile = array(); + /** + * array of parsed functions organized by the full path of the file that contains the function. + * Format: + * array(full path => array(functionname => {@link parserFunction})) + * @var array + */ + var $functionsbyfile = array(); + /** + * array of parsed defines organized by the full path of the file that contains the define. + * Format: + * array(full path => array(definename => {@link parserDefine})) + * @var array + */ + var $definesbyfile = array(); + /** + * array of parsed global variables organized by the full path of the file that contains the global variable definition. + * Format: + * array(full path => array(globalname => {@link parserGlobal})) + * @var array + */ + var $globalsbyfile = array(); + /** + * array of file names organized by functions that are in the file. + * This structure is designed to handle name conflicts. Two files can contain functions with the same name, and this array will + * record both filenames to help control namespace errors + * Format: + * array(functionname => array(full path of file containing functionname, full path of file 2 containing functionname...) + * @var array + */ + var $functionsbynamefile = array(); + /** + * array of file names organized by defines that are in the file. + * This structure is designed to handle name conflicts. Two files can contain defines with the same name, and this array will + * record both filenames to help control namespace errors + * Format: + * array(definename => array(full path of file containing definename, full path of file 2 containing definename...) + * @var array + */ + var $definesbynamefile = array(); + /** + * array of file names organized by global variables that are in the file. + * This structure is designed to handle name conflicts. Two files can contain global variables with the same name, and this array will + * record both filenames to help control namespace errors + * Format: + * array(global variablename => array(full path of file containing global variablename, full path of file 2 containing global variablename...) + * @var array + */ + var $globalsbynamefile = array(); + /** + * array of packages ordered by full path + * Format: + * array(fullpath => array(packagename,subpackagename)) + * @var array + */ + var $pagepackages = array(); + /** + * array of packages assigned to classes in a file, ordered by fullpath + * Format: + * array(fullpath => array(packagename => array(subpackagename => 1,subpackagename => 1,..),packagename2 =>...) + * @var array + */ + var $pageclasspackages = array(); + /** + * Namespace conflicts within all documented packages of functions + * Format: + * array(functionname => array(full path, full path,...)) + * @var array + */ + var $functionconflicts = array(); + /** + * Namespace conflicts within all documented pages + * Format: + * array(pagename => array(fullpath, fullpath,...)) + * @var array + */ + var $pageconflicts = array(); + /** + * Namespace conflicts within all documented packages of functions + * Format: + * array(functionname => array(full path, full path,...)) + * @var array + */ + var $defineconflicts = array(); + /** + * Namespace conflicts within all documented packages of functions + * Format: + * array(functionname => array(full path, full path,...)) + * @var array + */ + var $globalconflicts = array(); + /** @access private + * @var array */ + var $revcpbf = array(); + /** @access private + * @var boolean */ + var $packagesetup = false; + + /** + * sets up the {@link $pages} array + * @param parserPage &$element + */ + function addPage(&$element) + { + $this->curfile = $element->getPath(); + $this->pages[$element->getFile()][$element->getPath()] = $element; + $this->pathpages[$this->curfile] = $element->getFile(); + $this->addPagePackage($this->curfile, $element->package, $element->subpackage); + } + + /** + * moves a page from the {@link $pages} array to the {@link $ignorepages} array + * @param parserPage &$element + */ + function ignorePage(&$element) + { + $this->ignorepages[$element->getFile()][$element->getPath()] = $this->pages[$element->getFile()][$element->getPath()]; + unset($this->pages[$element->getFile()][$element->getPath()]); + } + + function getPathInfo($path,&$c) + { + $path = str_replace('/',SMART_PATH_DELIMITER,$path); + $info = array(); + if (!isset($this->pathpages[$path])) return false; + $p = $this->pages[$this->pathpages[$path]][$path]; + $p->name = $c->getPageName($p); + $info['package'] = $p->package; + $info['subpackage'] = $p->subpackage; + $info['name'] = $p->getFile(); + $info['source_loc'] = $p->getSourceLocation($c); + $x = new pageLink; + $x->addLink($p->path,$p->name,$p->file,$p->package, $p->subpackage); + $info['docs'] = $c->returnSee($x); + return $info; + } + + /** + * Change a page's name from its file to alias $name + * + * This function is used to handle a @name tag in a page-level DocBlock + * @param string $name + */ + function setName($name) + { + $this->pages[$name][$this->curfile] = $this->pages[$this->pathpages[$this->curfile]][$this->curfile]; + $this->pages[$name][$this->curfile]->file = $name; + unset($this->pages[$this->pathpages[$this->curfile]][$this->curfile]); + $this->pathpages[$this->curfile] = $name; + } + + /** + * Changes the package of the page represented by $path + * + * changes package in both the {@link $pages} array and the {@link pagepackages} array + * @param string $path full path + * @param string $package + * @param string $subpackage + */ + function addPagePackage($path,$package,$subpackage) + { + $this->pages[$this->pathpages[$path]][$path]->package = $package; + $this->pages[$this->pathpages[$path]][$path]->subpackage = $subpackage; + $this->pagepackages[$path] = array($package, $subpackage); + if (isset($this->includesbyfile[$path])) + { + foreach($this->includesbyfile[$path] as $i => $el) + { + $el->package = $package; + $el->subpackage = $subpackage; + $this->includesbyfile[$path][$i] = $el; + } + } + if (isset($this->functionsbyfile[$path])) + { + foreach($this->functionsbyfile[$path] as $i => $el) + { + $el->package = $package; + $el->subpackage = $subpackage; + $this->functionsbyfile[$path][$i] = $el; + } + } + if (isset($this->definesbyfile[$path])) + { + foreach($this->definesbyfile[$path] as $i => $el) + { + $el->package = $package; + $el->subpackage = $subpackage; + $this->definesbyfile[$path][$i] = $el; + } + } + if (isset($this->globalsbyfile[$path])) + { + foreach($this->globalsbyfile[$path] as $i => $el) + { + $el->package = $package; + $el->subpackage = $subpackage; + $this->globalsbyfile[$path][$i] = $el; + } + } + } + + /** + * sets up the {@link $includesbyfile} array using {@link $curfile} + * @param parserInclude &$element + */ + function addInclude(&$element) + { + $this->includesbyfile[$this->curfile][] = $element; + } + + /** + * sets up the {@link $functionsbyfile} array using {@link $curfile} + * @param parserFunction &$element + */ + function addFunction(&$element) + { + if (isset($this->functionsbyfile[$this->curfile])) + { + foreach($this->functionsbyfile[$this->curfile] as $i => $function) + { + if ($function->getName() == $element->getName()) + { + addWarning(PDERROR_ELEMENT_IGNORED,'function',$element->getName(),$this->curfile); + return; + } + } + } + $this->functionsbyfile[$this->curfile][] = $element; + $this->functionsbynamefile[$element->getName()][] = $this->curfile; + } + + /** + * sets up the {@link $globalsbyfile} array using {@link $curfile} + * @param parserGlobal &$element + */ + function addGlobal(&$element) + { + if (isset($this->globalsbyfile[$this->curfile])) + { + foreach($this->globalsbyfile[$this->curfile] as $i => $global) + { + if ($global->getName() == $element->getName()) + { + addWarning(PDERROR_ELEMENT_IGNORED,'global variable',$element->getName(),$this->curfile); + return; + } + } + } + $this->globalsbyfile[$this->curfile][] = $element; + $this->globalsbynamefile[$element->getName()][] = $this->curfile; + } + + /** + * sets up the {@link $definesbyfile} array using {@link $curfile} + * @param parserDefine &$element + */ + function addDefine(&$element) + { + if (isset($this->definesbyfile[$this->curfile])) + { + foreach($this->definesbyfile[$this->curfile] as $i => $define) + { + if ($define->getName() == $element->getName()) + { + addWarning(PDERROR_ELEMENT_IGNORED,'define',$element->getName(),$this->curfile); + return; + } + } + } + $this->definesbyfile[$this->curfile][] = $element; + $this->definesbynamefile[$element->getName()][] = $this->curfile; + } + + /** + * Used to align an element with the package of its parent page prior to Conversion. + * @param parserElement &$element + */ + function replaceElement(&$element) + { + if ($element->type == 'define') + { + foreach($this->definesbyfile[$element->getPath()] as $i => $el) + { + if ($el->getName() == $element->getName()) + { + $this->definesbyfile[$element->getPath()][$i] = &$element; + } + } + } elseif ($element->type == 'global') + { + foreach($this->globalsbyfile[$element->getPath()] as $i => $el) + { + if ($el->getName() == $element->getName()) + { + $this->globalsbyfile[$element->getPath()][$i] = &$element; + } + } + } elseif ($element->type == 'include') + { + foreach($this->includesbyfile[$element->getPath()] as $i => $el) + { + if ($el->getName() == $element->getName()) + { + $this->includesbyfile[$element->getPath()][$i] = &$element; + } + } + } elseif ($element->type == 'function') + { + foreach($this->functionsbyfile[$element->getPath()] as $i => $el) + { + if ($el->getName() == $element->getName()) + { + $this->functionsbyfile[$element->getPath()][$i] = &$element; + } + } + } + } + + /** + * adds a package from a class to the current file + * @param string $file full path to the file that contains the class + * @param string $package package name + */ + function addClassPackageToFile($file,$package,$subpackage) + { + // don't care about default +// if ($package == $GLOBALS['phpDocumentor_DefaultPackageName']) +// $this->revcpbf[$file][$package][$subpackage] = 1; + if (!isset($this->revcpbf[$file][$package][$subpackage])) + { + $this->pageclasspackages[$file][$package][$subpackage] = 1; + } + $this->revcpbf[$file][$package][$subpackage] = 1; + } + + /** + * if there is one class package in a file, the parent path inherits the package if its package is default. + * helps with -po to avoid dumb bugs + */ + function setupPagePackages() + { + if ($this->packagesetup) return; + foreach($this->pageclasspackages as $fullpath => $packages) + { + if (isset($this->pagepackages[$fullpath])) + { + if ($this->pagepackages[$fullpath][0] == $GLOBALS['phpDocumentor_DefaultPackageName']) + { + if (count($packages) == 1) + { + list($package,$subpackage) = each($packages); + if (count($subpackage) == 1) list($subpackage,) = each($subpackage); + else $subpackage = ''; + $this->addPagePackage($fullpath,$package,$subpackage); + } + } + } + } + $this->packagesetup = true; + } + + /** + * extracts function, define, and global variable name conflicts within the same package and between different + * packages. No two elements with the same name are allowed in the same package, to keep automatic linking + * possible. + * @access private + */ + function setupConflicts(&$render) + { + + foreach($this->functionsbynamefile as $function => $paths) + { + if (count($paths) - 1) + { //conflict + $package = array(); + foreach($paths as $path) + { + // create a list of conflicting functions in each package + $package[$this->pagepackages[$path][0]][] = $path; + } + foreach($package as $pathpackages) + { + // if at least 2 functions exist in the same package, delete all but the first one and add warnings + if (count($pathpackages) - 1) + { + for($i=1; $i < count($pathpackages); $i++) + { + addWarning(PDERROR_ELEMENT_IGNORED,'function',$function,$pathpackages[$i]); + foreach($this->functionsbyfile[$pathpackages[$i]] as $j => $blah) + { + if ($this->functionsbyfile[$pathpackages[$i]][$j]->getName() == $function) + unset($this->functionsbyfile[$pathpackages[$i]][$j]); + } + $oth = array_flip($paths); + unset($paths[$oth[$pathpackages[$i]]]); + } + } + } + $this->functionconflicts[$function] = $paths; + } + } + + foreach($this->definesbynamefile as $define => $paths) + { + if (count($paths) - 1) + { //conflict + $package = array(); + foreach($paths as $path) + { + // create a list of conflicting functions in each package + $package[$this->pagepackages[$path][0]][] = $path; + } + foreach($package as $pathpackages) + { + // if at least 2 functions exist in the same package, delete all but the first one and add warnings + if (count($pathpackages) - 1) + { + for($i=1; $i < count($pathpackages); $i++) + { + addWarning(PDERROR_ELEMENT_IGNORED,'define',$define,$pathpackages[$i]); + foreach($this->definesbyfile[$pathpackages[$i]] as $j => $blah) + { + if ($this->definesbyfile[$pathpackages[$i]][$j]->getName() == $define) + unset($this->definesbyfile[$pathpackages[$i]][$j]); + } + $oth = array_flip($paths); + unset($paths[$oth[$pathpackages[$i]]]); + } + } + } + $this->defineconflicts[$define] = $paths; + } + } + + foreach($this->globalsbynamefile as $global => $paths) + { + if (count($paths) - 1) + { //conflict + $package = array(); + foreach($paths as $path) + { + // create a list of conflicting functions in each package + $package[$this->pagepackages[$path][0]][] = $path; + } + foreach($package as $pathpackages) + { + // if at least 2 functions exist in the same package, delete all but the first one and add warnings + if (count($pathpackages) - 1) + { + for($i=1; $i < count($pathpackages); $i++) + { + addWarning(PDERROR_ELEMENT_IGNORED,'global variable',$global,$pathpackages[$i]); + foreach($this->globalsbyfile[$pathpackages[$i]] as $j => $blah) + { + if ($this->globalsbyfile[$pathpackages[$i]][$j]->getName() == $global) + unset($this->globalsbyfile[$pathpackages[$i]][$j]); + } + $oth = array_flip($paths); + unset($paths[$oth[$pathpackages[$i]]]); + } + } + } + $this->globalconflicts[$global] = $paths; + } + } + + foreach($this->pages as $name => $pages) + { + if (count($pages) - 1) + { // possible conflict + + } + } + } + + /** + * called by {@link parserFunction::getConflicts()} to get inter-package conflicts, should not be called directly + * @access private + * @return array Format: (package => {@link parserFunction} of conflicting function) + */ + function getFuncConflicts($name) + { + if (!isset($this->functionconflicts[$name])) return false; + $a = array(); + foreach($this->functionconflicts[$name] as $conflict) + { + foreach($this->functionsbyfile[$conflict] as $i => $func) + { + if ($func->getName() == $name) + $a[$this->functionsbyfile[$conflict][$i]->docblock->package] = $this->functionsbyfile[$conflict][$i]; + } + } + return $a; + } + + /** + * called by {@link parserGlobal::getConflicts()} to get inter-package conflicts, should not be called directly + * @access private + * @return array Format: (package => {@link parserGlobal} of conflicting global variable) + */ + function getGlobalConflicts($name) + { + if (!isset($this->globalconflicts[$name])) return false; + $a = array(); + foreach($this->globalconflicts[$name] as $conflict) + { + foreach($this->globalsbyfile[$conflict] as $i => $func) + { + if ($func->getName() == $name) + $a[$this->globalsbyfile[$conflict][$i]->docblock->package] = $this->globalsbyfile[$conflict][$i]; + } + } + return $a; + } + + /** + * called by {@link parserDefine::getConflicts()} to get inter-package conflicts, should not be called directly + * @access private + * @return array Format: (package => {@link parserDefine} of conflicting define) + */ + function getDefineConflicts($name) + { + if (!isset($this->defineconflicts[$name])) return false; + $a = array(); + foreach($this->defineconflicts[$name] as $conflict) + { + foreach($this->definesbyfile[$conflict] as $i => $func) + { + if ($func->getName() == $name) + $a[$this->definesbyfile[$conflict][$i]->docblock->package] = $this->definesbyfile[$conflict][$i]; + } + } + return $a; + } + + /** + * Adjusts packages of all pages and removes name conflicts within a package + * + * Automatic linking requires that each linkable name have exactly one element associated with it. In other words, there + * cannot be two functions named foo() in the same package. This also adheres to php rules with one exception: + * + * + * if ($test == 3) + * { + * define('whatever','this thing'); + * } else + * { + * define('whatever','this other thing'); + * } + * + * + * phpDocumentor is not aware of conditional control structures because it would slow things down considerably. + * So, what phpDocumentor does is automatically ignore the second define and raise a warning. The warning can + * be eliminated with an @ignore tag on the second element like so: + * + * + * if ($test == 3) + * { + * define('whatever','this thing'); + * } else + * { + * /** @ignore {@*} + * define('whatever','this other thing'); + * } + * + * + * if there are two files that contain the same procedural elements in the same package (for example, + * a common configuration file common.php), they will also be ignored as if they were in the same file. The + * reasoning behind this is simple. A package is an indivisible set of files and classes that a user will + * include in their code. Name conflicts must be avoided to allow successful execution. + * + * This function also plays the all-important role of calling {@link phpDocumentor_IntermediateParser::addElementToPage()} in + * order to add processed elements to their pages for Conversion. + * @param phpDocumentor_IntermediateParser &$render + */ + function setupPages(&$render) + { + global $_phpDocumentor_setting; + phpDocumentor_out("\nProcessing Procedural Page Element Name Conflicts\n\n"); + flush(); + $this->setupPagePackages(); + $this->setupConflicts($render); +// phpDocumentor_out("\nProcessing Procedural Pages\n\n"); + foreach($this->pathpages as $path => $name) + { +// phpDocumentor_out("Processing $path\n"); + $a = $this->pagepackages[$path]; + $b = &$this->pages[$name][$path]; + $render->addPage($b, $path); + $render->addUses($b, $path); + if (isset($this->includesbyfile[$path])) + foreach($this->includesbyfile[$path] as $include) + { + $include->docblock->package = $a[0]; + $include->docblock->subpackage = $a[1]; + $render->addElementToPage($include,$path); + } + + if (isset($this->functionsbyfile[$path])) + foreach($this->functionsbyfile[$path] as $function) + { + $function->docblock->package = $a[0]; + $function->docblock->subpackage = $a[1]; + $render->addElementToPage($function,$path); + $render->addUses($function,$path); + } + + if (isset($this->definesbyfile[$path])) + foreach($this->definesbyfile[$path] as $define) + { + $define->docblock->package = $a[0]; + $define->docblock->subpackage = $a[1]; + $render->addElementToPage($define,$path); + $render->addUses($define,$path); + } + + if (isset($this->globalsbyfile[$path])) + foreach($this->globalsbyfile[$path] as $global) + { + $global->docblock->package = $a[0]; + $global->docblock->subpackage = $a[1]; + $render->addElementToPage($global,$path); + $render->addUses($global,$path); + } + } + } + + function setParseBase($pbase) + { + $this->_parsedbase = $pbase; + } + + /** + * @return false|parserPage returns matched parserPage if found + */ + function pathMatchesParsedFile($path, $infile) + { + $test = $this->getRealPath($path, $infile); + if (is_string($test)) + { + if (isset($this->pathpages[$test])) + return $this->pages[$this->pathpages[$test]][$test]; + if (PHPDOCUMENTOR_WINDOWS) $test = str_replace('/','\\',$test); + if (isset($this->pathpages[$test])) + { + $a = $this->pages[$this->pathpages[$test]][$test]; + if (is_array($a->packageOutput) && !in_array($a->package, $a->packageOutput)) + return false; + return $this->pages[$this->pathpages[$test]][$test]; + } + } else + { + foreach($test as $file) + { + if (isset($this->pathpages[$file])) + return $this->pages[$this->pathpages[$file]][$file]; + if (PHPDOCUMENTOR_WINDOWS) $file = str_replace('/','\\',$file); + if (isset($this->pathpages[$file])) + { + $a = $this->pages[$this->pathpages[$file]][$file]; + if (is_array($a->packageOutput) && !in_array($a->package, $a->packageOutput)) + return false; + return $this->pages[$this->pathpages[$file]][$file]; + } + } + } + return false; + } + + /** + * @param string include() statement path to check + * @param string full path of file the statement is in + * @param string full path to base directory of parsing, used for . + * @return array|string returns an array of possible file locations or + * a string if there is an exact match + */ + function getRealPath($path, $file) + { + $curdir = str_replace('\\','/',dirname($file)); + $path = str_replace('\\','/',$path); + if (strpos($path,':') !== false) + { // windows, and we have a drive letter + return $path; + } elseif(strpos($path,'/') === 0) + { + return $path; + } + // not an absolute path + $path = explode('/',$path); + if ($path[0] == '.') + { + $path[0] = dirname($file); + return join($path,'/'); + } elseif ($path[0] == '..') + { + $dirfile = explode('/',dirname(str_replace('\\','/',$file))); + array_pop($dirfile); // remove the current directory + if (!count($dirfile)) return false; // we were at a top-level dir! + $path[0] = join($dirfile,'/'); // replace .. with parent dirname + return join($path,'/'); + } else + { + $path = join($path,'/'); + return array($curdir . PATH_DELIMITER . $path, + str_replace('\\','/',PHPDOCUMENTOR_BASE) . PATH_DELIMITER . $path); + } + } +} +?> \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Publisher.inc b/buildscripts/PhpDocumentor/phpDocumentor/Publisher.inc new file mode 100644 index 00000000..7e038021 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Publisher.inc @@ -0,0 +1,84 @@ + + * @author Joshua Eichorn + * @version $Id: Publisher.inc,v 1.1 2005/10/17 18:36:57 jeichorn Exp $ + * @package phpDocumentor + */ +/** + * a class for handling the publishing of data + * + * @author Kellin + * @author Joshua Eichorn + * @version $Id: Publisher.inc,v 1.1 2005/10/17 18:36:57 jeichorn Exp $ + * @package phpDocumentor + */ +class Publisher +{ + /**#@+ + * @var array + */ + /** + * Array of references objects that have Subscribed to this publisher + */ + var $subscriber = array(); + + var $tokens = array(); + + var $pushEvent = array(); + var $popEvent = array(); + /**#@-*/ + + + /** + * Adds a subscriber to the {@link $subscriber} array(). + * if $event is '*', the publisher will use $object as the default event handler + * @param integer $event see {@link Parser.inc} PARSER_EVENT_* constants + * @param class $object any class that has a HandleEvent() method like {@link phpDocumentor_IntermediateParser::HandleEvent()} or {@link Classes::HandleEvent()} + */ + function subscribe($event, &$object) + { + $this->subscriber[$event] =& $object; + } + + /** + * @param integer $event see {@link Parser.inc} PARSER_EVENT_* constants + * @param mixed $data anything the subscribed event handler is expecting + */ + function publishEvent($event,$data) + { + + // see if there is a specific event handler + if (!empty($this->subscriber[$event])) + { + $this->subscriber[$event]->HandleEvent($event,$data); + } + else if (isset($this->subscriber['*']) && is_object($this->subscriber['*'])) // check to see if a generic handler exists + { + $this->subscriber['*']->HandleEvent($event,$data); + } + } +} +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Setup.inc.php b/buildscripts/PhpDocumentor/phpDocumentor/Setup.inc.php new file mode 100644 index 00000000..1d953088 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Setup.inc.php @@ -0,0 +1,785 @@ + + * @version $Revision: 1.6 $ + * @package phpDocumentor + * @since 1.2 + */ +error_reporting(E_ALL); +/** common settings */ +include_once("phpDocumentor/common.inc.php"); + +include_once("phpDocumentor/Io.inc"); +include_once("phpDocumentor/Publisher.inc"); +include_once("phpDocumentor/Classes.inc"); +include_once("phpDocumentor/ProceduralPages.inc"); +include_once("phpDocumentor/IntermediateParser.inc"); +include_once("phpDocumentor/WordParser.inc"); +include_once("phpDocumentor/EventStack.inc"); +include_once("phpDocumentor/ParserData.inc"); +include_once("phpDocumentor/InlineTags.inc"); +include_once("phpDocumentor/DocBlockTags.inc"); +include_once("phpDocumentor/DescHTML.inc"); +include_once("phpDocumentor/ParserDocBlock.inc"); +include_once("phpDocumentor/ParserElements.inc"); +include_once("phpDocumentor/Parser.inc"); +include_once("phpDocumentor/phpDocumentorTWordParser.inc"); +include_once("phpDocumentor/phpDocumentorTParser.inc"); +include_once("phpDocumentor/HighlightParser.inc"); +include_once("phpDocumentor/TutorialHighlightParser.inc"); +include_once("phpDocumentor/ParserDescCleanup.inc"); +include_once("phpDocumentor/PackagePageElements.inc"); +include_once("phpDocumentor/XMLpackagePageParser.inc"); +include_once("phpDocumentor/LinkClasses.inc"); +include_once("phpDocumentor/Converter.inc"); +include_once("phpDocumentor/Errors.inc"); +if (isset($_GET)) +{ +/** + * $interface is either 'web' or is not set at all + * @global array $interface + */ + if (isset($_GET['interface'])) $interface = $_GET['interface']; +/** + * $_phpDocumentor_setting is either the value from the web interface, or is set up by {@link Io::parseArgv()} + * @global array $_phpDocumentor_setting + */ + if (isset($_GET['setting'])) $_phpDocumentor_setting = $_GET['setting']; +} + +/** + * default package name, set using -dn --defaultpackagename + * @global string $GLOBALS['phpDocumentor_DefaultPackageName'] + * @name $phpDocumentor_DefaultPackageName + */ +$GLOBALS['phpDocumentor_DefaultPackageName'] = 'default'; + +/** + * default package name, set using -dn --defaultcategoryname + * @global string $GLOBALS['phpDocumentor_DefaultCategoryName'] + * @name $phpDocumentor_DefaultCategoryName + */ +$GLOBALS['phpDocumentor_DefaultCategoryName'] = 'default'; + +/** + * @package phpDocumentor + */ +class phpDocumentor_setup +{ + /** + * The main parser + * @var Parser|phpDocumentorTParser + */ + var $parse; + /** + * Used to parse command-line options + * @var Io + */ + var $setup; + /** + * Used to organize output from the Parser before Conversion + * @var phpDocumentor_IntermediateParser + */ + var $render = false; + /** + * Packages to create documentation for + * @var string + */ + var $packages = false; + /** + * contents of --filename commandline + * @tutorial phpDocumentor.howto.pkg#using.command-line.filename + * @var string + */ + var $files = ''; + /** + * contents of --directory commandline + * @tutorial phpDocumentor.howto.pkg#using.command-line.directory + * @var string + */ + var $dirs = ''; + /** + * contents of --hidden commandline + * @tutorial phpDocumentor.howto.pkg#using.command-line.hidden + * @var boolean + */ + var $hidden = false; + /** + * time that parsing was started, used for informative timing of output + * @access private + */ + var $parse_start_time; + /** + * contents of --ignore commandline + * @tutorial phpDocumentor.howto.pkg#using.command-line.ignore + * @var string + */ + var $ignore_files = array(); + /** + * Checks PHP version, makes sure it is 4.2.0+, and chooses the + * phpDocumentorTParser if version is 4.3.0+ + * @uses parseIni() + */ + function phpDocumentor_setup() + { + global $_phpDocumentor_cvsphpfile_exts; + if (!function_exists('is_a')) + { + print "phpDocumentor requires PHP version 4.2.0 or greater to function"; + exit; + } + + // set runtime to a large value since this can take quite a while + // we can only set_time_limit when not in safe_mode bug #912064 + if (!ini_get('safe_mode')) + { + set_time_limit(0); // unlimited runtime + } else + { + phpDocumentor_out("time_limit cannot be set since your in safe_mode, please edit time_limit in your php.ini to allow enough time for phpDocumentor to run"); + } + ini_set("memory_limit","256M"); + + $phpver = phpversion(); + $phpdocver = PHPDOCUMENTOR_VER; + if (isset($_GET['interface'])) { + $phpver = "$phpver"; + $phpdocver = "$phpdocver"; + } + phpDocumentor_out("PHP Version $phpver\n"); + phpDocumentor_out("phpDocumentor version $phpdocver\n\n"); + + $this->parseIni(); + // create new classes + $this->setup = new Io; + if (tokenizer_ext) + { + phpDocumentor_out("using tokenizer Parser\n"); + $this->parse = new phpDocumentorTParser; + } else + { + phpDocumentor_out("using default (slower) Parser - get PHP 4.3.0+ +and load the tokenizer extension for faster parsing (your version is ".phpversion()."\n"); + $this->parse = new Parser; + } + } + + /** + * Get phpDocumentor settings from a user configuration file + * @param string user configuration file + */ + function readConfigFile($file) + { + global $_phpDocumentor_setting, $_phpDocumentor_options; + // security + $file = str_replace(array('..','.ini','\\'),array('','','/'),$file); + if (is_file($file . '.ini')) + { + $_phpDocumentor_setting = phpDocumentor_parse_ini_file($file.'.ini'); + } else + { + if ('@DATA-DIR@' != '@'.'DATA-DIR@') + { + $configdir = str_replace('\\','/', '@DATA-DIR@/PhpDocumentor') . PATH_DELIMITER . 'user' . PATH_DELIMITER; + } else { + $configdir = str_replace('\\','/',$GLOBALS['_phpDocumentor_install_dir']) . PATH_DELIMITER . 'user' . PATH_DELIMITER; + } + if (isset($_phpDocumentor_options['userdir'])) $configdir = $_phpDocumentor_options['userdir']; + if (substr($configdir,-1) != '/') + { + $configdir .= '/'; + } + $_phpDocumentor_setting = phpDocumentor_parse_ini_file( $configdir . $file . '.ini'); + if (empty($_phpDocumentor_setting['defaultpackagename'])) + { + $_phpDocumentor_setting['defaultpackagename'] = 'default'; + } + } + // don't want a loop condition! + unset($_phpDocumentor_setting['useconfig']); + $this->readCommandLineSettings(); + } + + /** + * Get phpDocumentor settings from command-line or web interface + */ + function readCommandLineSettings() + { + global $_phpDocumentor_setting,$interface,$_phpDocumentor_RIC_files; + // subscribe $render class to $parse class events + if (!isset($interface) && !isset($_GET['interface']) && !isset($_phpDocumentor_setting)) + { + // Parse the argv settings + $_phpDocumentor_setting = $this->setup->parseArgv(); + } + if (isset($_phpDocumentor_setting['useconfig']) && !empty($_phpDocumentor_setting['useconfig'])) return $this->readConfigFile($_phpDocumentor_setting['useconfig']); + if (!isset($_phpDocumentor_setting['junk'])) $_phpDocumentor_setting['junk'] = ''; + if (!isset($_phpDocumentor_setting['title'])) $_phpDocumentor_setting['title'] = 'Generated Documentation'; + $temp_title = $_phpDocumentor_setting['title']; + $this->render = new phpDocumentor_IntermediateParser($temp_title); + if (isset($_phpDocumentor_setting['help']) || $_phpDocumentor_setting['junk'] == "-h" || $_phpDocumentor_setting['junk'] == "--help") + { + echo $this->setup->displayHelpMsg(); + die(); + } + + if (isset($_phpDocumentor_setting['hidden'])) $this->hidden = true; + + // set to parse elements marked private with @access private + if (isset($_phpDocumentor_setting['parseprivate']) && $_phpDocumentor_setting['parseprivate'] == 'on') + { + $this->render->setParsePrivate(true); + } + + if (isset($_phpDocumentor_setting['ignoretags'])) + { + $ignoretags = explode(',', $_phpDocumentor_setting['ignoretags']); + $ignoretags = array_map('trim', $ignoretags); + $tags = array(); + foreach($ignoretags as $tag) + { + if (!in_array($tag,array('@global', '@access', '@package', '@ignore', '@name', '@param', '@return', '@staticvar', '@var'))) + $tags[] = $tag; + } + $_phpDocumentor_setting['ignoretags'] = $tags; + } + + if (isset($_phpDocumentor_setting['readmeinstallchangelog'])) + { + $_phpDocumentor_setting['readmeinstallchangelog'] = explode(',',str_replace(' ','',$_phpDocumentor_setting['readmeinstallchangelog'])); + $rics = array(); + foreach($_phpDocumentor_setting['readmeinstallchangelog'] as $ric) + { + $rics[] = strtoupper(trim($ric)); + } + $_phpDocumentor_RIC_files = $rics; + } + + if (isset($_phpDocumentor_setting['javadocdesc']) && $_phpDocumentor_setting['javadocdesc'] == 'on') + { + $this->parse->eventHandlers[PARSER_EVENT_DOCBLOCK] = 'JavaDochandleDocblock'; + } + if (tokenizer_ext) + { + if (isset($_phpDocumentor_setting['sourcecode']) && $_phpDocumentor_setting['sourcecode'] == 'on') + { + $_phpDocumentor_setting['sourcecode'] = true; + } else + { + $_phpDocumentor_setting['sourcecode'] = false; + } + } else + { + if (isset($_phpDocumentor_setting['sourcecode']) && $_phpDocumentor_setting['sourcecode'] == 'on') + { + addWarning(PDERROR_SOURCECODE_IGNORED); + } + $_phpDocumentor_setting['sourcecode'] = false; + } + if (isset($_phpDocumentor_setting['converterparams'])) + { + $_phpDocumentor_setting['converterparams'] = explode($_phpDocumentor_setting['converterparams']); + foreach($_phpDocumentor_setting['converterparams'] as $i => $p) + { + $_phpDocumentor_setting['converterparams'][$i] = trim($p); + } + } + if (isset($_phpDocumentor_setting['customtags']) && !empty($_phpDocumentor_setting['customtags'])) + { + $c = explode(',',$_phpDocumentor_setting['customtags']); + for($i=0;$irender->setQuietMode(true); + } + + // Setup the different classes + if (isset($_phpDocumentor_setting['templatebase'])) + { + $this->render->setTemplateBase($_phpDocumentor_setting['templatebase']); + } + if (isset($_phpDocumentor_setting['target']) && !empty($_phpDocumentor_setting['target'])) + { + $this->render->setTargetDir($_phpDocumentor_setting['target']); + } + else + { + echo "a target directory must be specified\n try phpdoc -h\n"; + die(); + } + if (!empty($_phpDocumentor_setting['packageoutput'])) + { + $this->packages = explode(",",$_phpDocumentor_setting['packageoutput']); + foreach($this->packages as $p => $v) + { + $this->packages[$p] = trim($v); + } + } + if (!empty($_phpDocumentor_setting['filename'])) + $this->files = $_phpDocumentor_setting['filename']; + if (!empty($_phpDocumentor_setting['directory'])) + $this->dirs = $_phpDocumentor_setting['directory']; + } + + function checkIgnoreTag($tagname, $inline = false) + { + global $_phpDocumentor_setting; + $tagname = '@'.$tagname; + if (!isset($_phpDocumentor_setting['ignoretags'])) return false; + if ($inline) $tagname = '{'.$tagname.'}'; + return in_array($tagname, $_phpDocumentor_setting['ignoretags']); + } + + function setJavadocDesc() + { + $this->parse->eventHandlers[PARSER_EVENT_DOCBLOCK] = 'JavaDochandleDocblock'; + } + + function setParsePrivate() + { + $this->render->setParserPrivate(true); + } + + function setQuietMode() + { + $this->render->setQuietMode(true); + } + + function setTargetDir($target) + { + $this->render->setTargetDir($target); + } + + function setTemplateBase($dir) + { + $this->render->setTemplateBase($dir); + } + + function setPackageOutput($po) + { + $this->packages = explode(",",$po); + } + + function setTitle($ti) + { + $this->render = new phpDocumentor_IntermediateParser($ti); + } + + function setFilesToParse($files) + { + $this->files = $files; + } + + function setDirectoriesToParse($dirs) + { + $this->dirs = $dirs; + } + + function parseHiddenFiles() + { + $this->hidden = true; + } + + function setIgnore($ig) + { + if (strstr($ig,",")) + { + $this->ignore_files = explode(",",$ig); + } else { + if (!empty($ig)) + $this->ignore_files = array($ig); + } + $this->ignore_files = array_map('trim', $this->ignore_files); + } + + function createDocs($title = false) + { + $this->parse_start_time = time(); + global $_phpDocumentor_setting; + if (!$this->render) + { + $this->render = new phpDocumentor_IntermediateParser($title); + } + // setup ignore list + $this->ignore_files =array(); + if(isset($_phpDocumentor_setting['ignore'])) + { + $this->setIgnore($_phpDocumentor_setting['ignore']); + } + $this->parse->subscribe("*",$this->render); + // parse the directory + if (!empty($this->files)) + { + $files = explode(",",$this->files); + foreach($files as $file) + { + $file = trim($file); + $test = $this->setup->getAllFiles($file); + if ($test) + { + foreach($test as $file) + { + $file = trim($file); + $dir = realpath(dirname($file)); + $dir = strtr($dir, "\\", "/"); + $dir = str_replace('//','/',$dir); + // strip trailing directory seperator + if (substr($dir,-1) == "/" || substr($dir,-1) == "\\") + { + $dir = substr($dir,0,-1); + } + $file = strtr(realpath($file), "\\", "/"); + $file = str_replace('//','/',$file); + + if (!$this->setup->checkIgnore(basename($file),dirname($file),$this->ignore_files)) + { + $filelist[] = str_replace('\\','/',$file); + } else { + phpDocumentor_out("File $file Ignored\n"); + flush(); + } + } + } else + { + $dir = realpath(dirname(realpath($file))); + $dir = strtr($dir, "\\", "/"); + $dir = str_replace('//','/',$dir); + // strip trailing directory seperator + if (substr($dir,-1) == "/" || substr($dir,-1) == "\\") + { + $dir = substr($dir,0,-1); + } + $base = count(explode("/",$dir)); + $file = strtr(realpath($file), "\\", "/"); + $file = str_replace('//','/',$file); + flush(); + + if (!$this->setup->checkIgnore(basename($file),dirname($file),$this->ignore_files)) + { + $filelist[] = str_replace('\\','/',$file); + } else { + phpDocumentor_out("File $file Ignored\n"); + flush(); + } + } + } + } + if (!empty($this->dirs)) + { + $dirs = explode(",",$this->dirs); + foreach($dirs as $dir) + { + $dir = trim(realpath($dir)); + $dir = strtr($dir, "\\", "/"); + $dir = str_replace('//','/',$dir); + // strip trailing directory seperator + if (substr($dir,-1) == "/" || substr($dir,-1) == "\\") + { + $dir = substr($dir,0,-1); + } + $files = $this->setup->dirList($dir,$this->hidden); + if (is_array($files)) + { + foreach($files as $file) + { + // Make sure the file isn't a hidden file + $file = strtr($file, "\\", "/"); + if (substr(basename($file),0,1) != ".") + { + if (!$this->setup->checkIgnore(basename($file),str_replace('\\','/',dirname($file)),$this->ignore_files)) + { + $filelist[] = str_replace('\\','/',$file); + } else { + phpDocumentor_out("File $file Ignored\n"); + flush(); + } + } + } + } + } + } + if (isset($filelist)) + { + if (PHPDOCUMENTOR_WINDOWS) + { + // case insensitive array_unique + usort($filelist,'strnatcasecmp'); + reset($filelist); + + $newarray = array(); + $i = 0; + + $element = current($filelist); + for ($n=0;$nsetup->getBase($filelist))); + define("PHPDOCUMENTOR_BASE",$source_base); + list($filelist,$ric) = $this->setup->getReadmeInstallChangelog($source_base, $filelist); + phpDocumentor_out("\n\nGrabbing README/INSTALL/CHANGELOG\n"); + flush(); + foreach($ric as $file) + { + phpDocumentor_out(basename($file).'...'); + flush(); + $fp = fopen($file,'r'); + $contents = fread($fp,filesize($file)); + $this->render->HandleEvent(PHPDOCUMENTOR_EVENT_README_INSTALL_CHANGELOG, array(basename($file),$contents)); + fclose($fp); + } + phpDocumentor_out("\ndone\n"); + flush(); + list($filelist,$tutorials) = $this->setup->getTutorials($filelist); + phpDocumentor_out("\n\nTutorial/Extended Documentation Parsing Stage\n\n"); + flush(); + if (count($tutorials)) + { + $tuteparser = new XMLPackagePageParser; + $tuteparser->subscribe('*',$this->render); + foreach($tutorials as $tutorial) + { + switch($tutorial['tutetype']) + { + case 'pkg' : + case 'cls' : + case 'proc' : + switch($tutorial['tutetype']) + { + case 'pkg' : + $ptext = 'Package-level Docs '; + if (!empty($tutorial['subpackage'])) + $ptext = 'Sub-Package Docs '; + break; + case 'cls' : + $ptext = 'Class-level Docs '; + break; + case 'proc' : + $ptext = 'Procedural-level Docs '; + break; + } + $fp = @fopen($tutorial['path'],"r"); + if ($fp) + { + $ret = fread($fp,filesize($tutorial['path'])); + // fix 1151650 + if (stristr($ret, "utf-8") !== "") + { + $ret = utf8_decode($ret); + } + fclose($fp); + unset($fp); + phpDocumentor_out('Parsing '.$ptext.$tutorial['path'].'...'); + flush(); + $tuteparser->parse($ret,$tutorial); + phpDocumentor_out("done\n"); + flush(); + } else + { + phpDocumentor_out('Error '.$ptext.$tutorial['path'].' doesn\'t exist'."\n"); + flush(); + } + default : + break; + } + } + } + phpDocumentor_out("done\n"); + flush(); + phpDocumentor_out("\n\nGeneral Parsing Stage\n\n"); + flush(); + foreach($filelist as $file) + { + phpDocumentor_out("Reading file $file"); + flush(); + $this->parse->parse($a = $this->setup->readPhpFile($file, $this->render->quietMode),$file,$base,$this->packages); + + } + $b = (time() - $this->parse_start_time); + phpDocumentor_out("done\n"); + flush(); + // render output + phpDocumentor_out("\nConverting From Abstract Parsed Data\n"); + flush(); + $this->render->output(); + $a = (time() - $this->parse_start_time); + $c = ($a - $b); + phpDocumentor_out("\nParsing time: $b seconds\n"); + phpDocumentor_out("\nConversion time: $c seconds\n"); + phpDocumentor_out("\nTotal Documentation Time: $a seconds\n"); + phpDocumentor_out("done\n"); + flush(); + } else + { + print "ERROR: nothing parsed"; + exit; + } + } + /** + * Parse configuration file phpDocumentor.ini + */ + function parseIni() + { + phpDocumentor_out("Parsing configuration file phpDocumentor.ini..."); + flush(); + if ('@DATA-DIR@' != '@'.'DATA-DIR@') + { + $options = phpDocumentor_parse_ini_file(str_replace('\\','/', '@DATA-DIR@/PhpDocumentor') . PATH_DELIMITER . 'phpDocumentor.ini',true); + } else { + $options = phpDocumentor_parse_ini_file(str_replace('\\','/',$GLOBALS['_phpDocumentor_install_dir']) . PATH_DELIMITER . 'phpDocumentor.ini',true); + } + + if (!$options) + { + print "ERROR: cannot open phpDocumentor.ini in directory " . $GLOBALS['_phpDocumentor_install_dir']."\n"; + print "-Is phpdoc in either the path or include_path in your php.ini file?"; + exit; + } + + foreach($options as $var => $values) + { + if ($var != 'DEBUG') + { +// phpDocumentor_out("\n$var"); + if ($var != '_phpDocumentor_setting' && $var != '_phpDocumentor_options' && $var != '_phpDocumentor_install_dir' ) $values = array_values($values); +// fancy_debug("\n$var",$values); + $GLOBALS[$var] = $values; + } + } + phpDocumentor_out("\ndone\n"); + flush(); + /** Debug Constant */ + define("PHPDOCUMENTOR_DEBUG",$options['DEBUG']['PHPDOCUMENTOR_DEBUG']); + define("PHPDOCUMENTOR_KILL_WHITESPACE",$options['DEBUG']['PHPDOCUMENTOR_KILL_WHITESPACE']); + $GLOBALS['_phpDocumentor_cvsphpfile_exts'] = $GLOBALS['_phpDocumentor_phpfile_exts']; + foreach($GLOBALS['_phpDocumentor_cvsphpfile_exts'] as $key => $val) + { + $GLOBALS['_phpDocumentor_cvsphpfile_exts'][$key] = "$val,v"; + } + // none of this stuff is used anymore + if (isset($GLOBALS['_phpDocumentor_html_allowed'])) + { + $___htmltemp = array_flip($GLOBALS['_phpDocumentor_html_allowed']); + $___html1 = array(); + foreach($___htmltemp as $tag => $trans) + { + $___html1['<'.$tag.'>'] = htmlentities('<'.$tag.'>'); + $___html1[''] = htmlentities(''); + } + $GLOBALS['phpDocumentor___html'] = array_flip($___html1); + } + } + + function setupConverters($output = false) + { + global $_phpDocumentor_setting; + if ($output) + { + $_phpDocumentor_setting['output'] = $output; + } + if (isset($_phpDocumentor_setting['output']) && !empty($_phpDocumentor_setting['output'])) + { + $c = explode(',',$_phpDocumentor_setting['output']); + for($i=0; $i< count($c); $i++) + { + $c[$i] = explode(':',$c[$i]); + $a = $c[$i][0]; + $b = false; + $d = 'default/'; + if (count($c[$i]) > 1) + { + $a = $c[$i][0]; + $b = $c[$i][1]; + if (isset($c[$i][2])) + { + $d = $c[$i][2]; + $d = str_replace("\\","/",$d); + if (substr($d,-1) != "/") + { + $d .= "/"; + } + } + else $d = 'default/'; + } + if (strtoupper(trim($a)) == 'HTML' && (trim($b) == 'default')) + { + phpDocumentor_out("WARNING: HTMLdefaultConverter is deprecated, using HTMLframesConverter.\n"); + phpDocumentor_out("WARNING: template output is identical, HTMLframes is more flexible.\n"); + phpDocumentor_out("WARNING: please adjust your usage\n"); + flush(); + $b = 'frames'; // change default to frames. + } + $this->render->addConverter(strtoupper(trim($a)),trim($b),trim($d)); + } + } else + { + $this->render->addConverter('HTML','frames','default/'); + } + if (empty($this->render->converters)) addErrorDie(PDERROR_NO_CONVERTERS); + } +} + +/** + * Print parse information if quiet setting is off + */ +function phpDocumentor_out($string) +{ + global $_phpDocumentor_setting; + if (!isset($_phpDocumentor_setting['quiet']) || !$_phpDocumentor_setting['quiet']) + { + print $string; + } + +} +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/BUGS b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/BUGS new file mode 100644 index 00000000..fcbe48af --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/BUGS @@ -0,0 +1,7 @@ +Smarty is supported only in PHP 4.0.6 or later. + +Smarty versions previous to 2.0 require the PEAR libraries. Be sure to include +the path to the PEAR libraries in your php include_path. Config_file.class.php +uses the PEAR library for its error handling routines. PEAR comes with the PHP +distribution. Unix users check /usr/local/lib/php, windows users check +C:/php/pear. diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/COPYING.lib b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/COPYING.lib new file mode 100644 index 00000000..3b204400 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/COPYING.lib @@ -0,0 +1,458 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/ChangeLog b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/ChangeLog new file mode 100644 index 00000000..6dcda589 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/ChangeLog @@ -0,0 +1,5421 @@ +2003-11-18 Messju Mohr + + * NEWS + libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + move Smarty::quote_replace() to Smarty_Compiler::_quote_replace() + + * libs/Smarty.class.php: + removed extract-calls from _include()- and _eval()-wrappers + variables passed with {include_php} have to accessed as members of $params + now + +2003-11-17 Messju Mohr + + * docs/designers.sgml: + fixed typo + +2003-11-13 Messju Mohr + + * libs/Config_File.class.php: + fix occasional notice + +2003-11-13 andreas halter + + * docs/de/designers.sgml: + - added cat modifier, thanks messju :-) + +2003-11-13 Monte Ohrt + + * (Smarty_2_6_0-RC3) + NEWS + libs/Config_File.class.php + libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + commit RC3 tags + +2003-11-13 Messju Mohr + + * NEWS + libs/Smarty_Compiler.class.php: + fix handling of $var.key inside [] + + * libs/Smarty.class.php: + fix unnecessary loading of core.load_resource_plugin.php + + * (Smarty_2_6_0-RC3) + docs/fr/designers.sgml: + fixed example of html_table + +2003-11-11 Messju Mohr + + * NEWS + libs/core/core.process_cached_inserts.php: + fix handling of assign inside {insert}-tags + +2003-11-06 Messju Mohr + + * libs/core/core.read_cache_file.php: + added $exp_time-parameter + + * docs/programmers.sgml: + added $exp_time to cache_handler_func-example + + * libs/Smarty.class.php + libs/core/core.write_cache_file.php: + added $exp_time-parameter of clear_cache() and clear_all_cache() to + cache_handler_func. + +2003-11-05 Messju Mohr + + * NEWS + libs/Config_File.class.php: + fix handling if [...] inside triple-quotes in config-files + +2003-11-04 Messju Mohr + + * libs/Smarty.class.php: + fixed little bug in _parse_resource_name() (jlgunter, messju) + +2003-11-03 andreas halter + + * docs/designers.sgml + docs/de/designers.sgml + docs/fr/designers.sgml: + - changed Smarty.php.class occurences to Smarty.class.php + +2003-10-29 boots + + * docs/appendixes.sgml + docs/designers.sgml + docs/manual.sgml + docs/programmers.sgml + docs/de/appendixes.sgml + docs/de/designers.sgml + docs/de/programmers.sgml + docs/fr/appendixes.sgml + docs/fr/designers.sgml + docs/fr/getting-started.sgml + docs/fr/manual.sgml + docs/fr/preface.sgml + docs/fr/programmers.sgml: + Fixes to documentation syntax so that all content can be processed used + xsltproc docbook-xsl tools. In particular, fixes unescaped entities, + broken tags, unquoted attributes. + +2003-10-27 Messju Mohr + + * NEWS + libs/Smarty_Compiler.class.php: + fix handling of simple-math-operators inside modifiers + +2003-10-25 Messju Mohr + + * libs/Smarty_Compiler.class.php: + removed unused property _output_type + removed unused param $tag_attrs of _parse_var_props() + cleaned up alignment of class-properties + +2003-10-23 Messju Mohr + + * libs/Smarty_Compiler.class.php: + removed notice in php-tag handling in Smarty_Compiler::_compile_file() + + * libs/Smarty_Compiler.class.php: + removed two occasional E_NOTICES from + Smarty_Compiler::_compile_include_php_tag() + + * NEWS + libs/core/core.create_dir_structure.php: + fix handling of trailing-slashes in open_basedir in + smarty_core_create_dir_structure() + +2003-10-20 Messju Mohr + + * libs/Smarty_Compiler.class.php: + elements inside `` are bracketed now inside the compiled-tpl. this + fixes some issues with simple-math inside backticks. + +2003-10-16 Monte Ohrt + + * docs/designers.sgml: + update overlib docs, no working examples + +2003-10-12 Messju Mohr + + * libs/Smarty.class.php + libs/core/core.is_secure.php: + move check for template_dir in secure_dir-array into core.is_secure.php + + this makes template_exists() work correctly with security=true even if + template_dir is not inside the secure_dir-array + +2003-10-11 Messju Mohr + + * libs/plugins/shared.make_timestamp.php: + tightened check for YYYYMMDDHHMMSS-format. thanks konstantin for + pointing this out. + + removed a few tabs. + + * libs/Smarty_Compiler.class.php: + fix precedence of simple-math-operators before modifiers. + thanks dominik! + + * libs/Config_File.class.php + libs/Smarty.class.php + libs/Smarty_Compiler.class.php + libs/core/core.assemble_plugin_filepath.php + libs/core/core.assign_smarty_interface.php + libs/core/core.create_dir_structure.php + libs/core/core.display_debug_console.php + libs/core/core.get_include_path.php + libs/core/core.get_microtime.php + libs/core/core.get_php_resource.php + libs/core/core.is_secure.php + libs/core/core.is_trusted.php + libs/core/core.load_plugins.php + libs/core/core.load_resource_plugin.php + libs/core/core.process_cached_inserts.php + libs/core/core.process_compiled_include.php + libs/core/core.read_cache_file.php + libs/core/core.rm_auto.php + libs/core/core.rmdir.php + libs/core/core.run_insert_handler.php + libs/core/core.smarty_include_php.php + libs/core/core.write_compiled_include.php + libs/core/core.write_compiled_resource.php + libs/core/core.write_file.php: + removed tabs from the main and the core/*.php files + +2003-10-08 Monte Ohrt + + * (Smarty_2_6_0-RC2) + NEWS + libs/Config_File.class.php + libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + update version numbers to RC2 + +2003-09-18 Messju Mohr + + * docs/designers.sgml + docs/de/designers.sgml: + fixed description of cycle's advance-attribute + +2003-09-16 Messju Mohr + + * NEWS + libs/Smarty_Compiler.class.php: + apply modifiers only once to section-loop and foreach-from attributes + +2003-09-15 Messju Mohr + + * libs/Smarty.class.php + libs/Smarty_Compiler.class.php + libs/core/core.write_cache_paths_file.php: + backed out _smarty_cached_paths-file-handling + + * libs/Smarty.class.php + libs/core/core.rm_auto.php: + fixed clear_compiled_tpl with explicit $tpl_file given + fixed return value of smarty_core_rm_auto() + Smarty::_unlink() + + * libs/Smarty.class.php: + little fix in _get_auto_filename() + +2003-09-14 Messju Mohr + + * libs/Smarty.class.php + libs/core/core.assemble_auto_filename.php: + removed auto-filenames from path-cache. merged assemble_auto_filename + back into Smarty::_get_auto_filename() + +2003-09-12 Messju Mohr + + * libs/Smarty_Compiler.class.php: + fixed quoting of modifier parameters + + * NEWS + libs/Smarty.class.php + libs/Smarty_Compiler.class.php + libs/core/core.get_php_resource.php + libs/core/core.load_plugins.php + libs/core/core.load_resource_plugin.php: + remove Smarty::_plugin_implementation_exists() - use php's native + is_callable() + +2003-09-11 Messju Mohr + + * libs/Smarty.class.php: + silenced two notices acces HTTP_SERVER_VARS + +2003-09-10 andreas halter + + * docs/de/designers.sgml + docs/de/getting-started.sgml + docs/de/programmers.sgml: + - minor fixes (2 rep), slight wording changes + - jade transform problem fixed + +2003-09-08 andreas halter + + * docs/de/designers.sgml + docs/de/getting-started.sgml + docs/de/manual.sgml + docs/de/preface.sgml + docs/de/programmers.sgml: + all updated for 2.6.0 release, translated everything from 2_5_0 branch to + 20030908 + +2003-09-04 Messju Mohr + + * libs/Smarty.class.php: + proper checking for files in _fetch_resource_info() + +2003-09-02 Messju Mohr + + * NEWS + libs/Smarty_Compiler.class.php: + ignore {strip}/{/strip) inside {strip}-blocks + + * libs/plugins/function.mailto.php: + fixed 2 notices in smarty_function_mailto() + +2003-09-01 Messju Mohr + + * libs/Smarty.class.php: + re-include cache_paths on multiple calls to fetch() to avoid + inconsistencies + at multiple calls to fetch() in one script + + * libs/Smarty_Compiler.class.php: + fixed handling of \r in {strip} + renamed $_trailing_lf to $_additional_newline + + * libs/Smarty_Compiler.class.php: + the weekly fix for {strip} :) + + * docs/designers.sgml: + fixed example for simple math. + +2003-08-29 Messju Mohr + + * libs/core/core.assign_smarty_interface.php + libs/core/core.display_debug_console.php + libs/plugins/function.assign.php + libs/plugins/function.html_options.php + libs/plugins/function.html_table.php: + fixed PHPDocumentor-comments (thanks Konstantin) + + * libs/core/core.rmdir.php: + made rmdir a bit more optimistic. especially it now removes + directories correctly that where created accidently by "safe_mode=On + && $use_sub_dirs=true" + +2003-08-27 Messju Mohr + + * NEWS + libs/Smarty_Compiler.class.php: + fixed removal of leading/trailing newlines in {strip}-blocks + +2003-08-25 Messju Mohr + + * INSTALL: + added note emphasizing the introduction of "libs/" with 2.5.0 + + * NEWS + libs/plugins/modifier.escape.php: + fixed proper escaping of " and ' with escape:javascript + +2003-08-22 Messju Mohr + + * NEWS + libs/core/core.assemble_plugin_filepath.php: + fixed bug in traversal of $smarty->plugins_dir-array in + smarty_core_assemble_plugin_filepath(). the first matching plugin in + the path should be used, not the last one. + + * libs/core/core.read_cache_file.php: + discard $_cache_info when the cache should be regenerated + +2003-08-20 Messju Mohr + + * NEWS + libs/Smarty_Compiler.class.php + libs/plugins/block.strip.php: + reverted {strip} from a block-plugin back into the compiler + + * docs/programmers.sgml: + fixed examples for register_function() and register_block() + + * libs/Smarty.class.php: + made template_exists() quiet when the template does not exist (thanks + to konstatin for pointing this out) + +2003-08-18 Monte Ohrt + + * docs/getting-started.sgml: + fix example title + + * docs/README + docs/getting-started.sgml: + change installation wording confusion + +2003-08-18 Messju Mohr + + * libs/Smarty.class.php + libs/core/core.read_cache_file.php: + fixed unnecessary load of source in template_exists() and the + compile-check of smarty_core_read_cache_file() + + * libs/Smarty_Compiler.class.php: + allow section-, array- and object-dereference in $smarty-references + +2003-08-15 Messju Mohr + + * docs/designers.sgml: + added parameter-descriptions for count_characters (thanks Konstantin + A. Pelepelin) + + fixed docs for {html_checkboxes} + +2003-08-14 Messju Mohr + + * libs/Smarty.class.php + libs/core/core.read_cache_file.php: + fixed timestamp-check of config-files in smarty_core_read_cache_file() + + * libs/Smarty.class.php: + fixed typecasting for arrays in _parse_resource_name() + + * NEWS + libs/plugins/function.config_load.php: + fixes in config_load: + - handling of section-attribute + - reusing the same config-file multiple times + - serialization of config-data for php<4.2.0 (no var_export) + + many thanks to atu for pointing this out and for testing + +2003-08-13 Messju Mohr + + * libs/Smarty.class.php + libs/core/core.smarty_include_php.php: + fixed problem with vars as attributes in {include_php} + +2003-08-13 Monte Ohrt + + * docs/README: + commit README file for documentation compiling + +2003-08-13 Messju Mohr + + * libs/debug.tpl + libs/plugins/modifier.debug_print_var.php: + removed '\r' from debug_print_vars' output + properly escape vars in javascript-version of debug.tpl + +2003-08-11 Monte Ohrt + + * (Smarty_2_6_0_RC1) + NEWS + docs/designers.sgml + docs/html.dsl + docs/php.dsl + libs/Config_File.class.php + libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + get ready for 2.6.0-RC1 release + +2003-08-10 Messju Mohr + + * NEWS + libs/Smarty.class.php: + fixed status-header for cache_modified_check under cgi-sapi + +2003-08-09 Messju Mohr + + * libs/core/core.is_secure.php + libs/core/core.is_trusted.php: + synced secure_dir-checking with trusted_dir-checking + + * libs/core/core.is_secure.php: + tightenend path checking in smarty_core_is_secure() + +2003-08-08 Messju Mohr + + * libs/Smarty.class.php: + fix: proper nesting of $smarty->_cache_including flag in cascaded + cached/not-cached/fetched/inserted/foo-templates + + * libs/debug.tpl: + better escaping for $_debug_tpls[templates].filenames + + * libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + removed redundant $smarty from Smarty::_smarty_include() + + * libs/debug.tpl: + proper escaping of filenames in debug-console (thanks to prossel). + +2003-08-07 Messju Mohr + + * docs/programmers.sgml: + added docs for block-methods of registered objects + + * docs/programmers.sgml: + fixed typo in example for registered objects + + * docs/designers.sgml: + fixed exampls of html_image and html_checkboxes + + * libs/plugins/function.debug.php: + fixed {debug} and removed tabs in function.debug.php + + * docs/programmers.sgml: + fixed example for register_object + + * docs/designers.sgml + docs/programmers.sgml: + updated docs for capture, html_table, html_image and register_object + +2003-08-07 Monte Ohrt + + * docs/designers.sgml + docs/programmers.sgml: + add math and default_resource_type to docs + + * docs/getting-started.sgml: + add core to example, add tech note + +2003-08-07 Messju Mohr + + * docs/manual.sgml + docs/fr/manual.sgml: + upd copyright in the docs + +2003-08-07 Monte Ohrt + + * docs/getting-started.sgml: + added core directory to install instructions + +2003-08-07 Messju Mohr + + * docs/designers.sgml + docs/programmers.sgml: + added docs for php-functions as modifiers + + * libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + better caching of attributes for $cacheable=false-plugins + + * docs/programmers.sgml: + added section "caching.cacheable" to the docs, explaining the usage of + the $cacheable-flag of the register_(block|compiler|function)-functions + + * libs/Smarty_Compiler.class.php: + fixed output of custom-functions with cached attributes + + * docs/programmers.sgml: + docs update on callbacks to the register_*-functions + +2003-08-06 Messju Mohr + + * NEWS + libs/Smarty.class.php + libs/Smarty_Compiler.class.php + libs/core/core.process_compiled_include.php: + added optional parameter $cache_attrs to register_function() and + register_block(). $cache_attrs is an array containing attribute- names + that should be cached on calls to functions that have $cacheable set + to false. + + * libs/Smarty.class.php: + fixed bug in _run_mod_handler + + * libs/Smarty_Compiler.class.php: + fixed bug with autoload-handling of modifiers. thanks ándre. + +2003-08-05 Messju Mohr + + * libs/Config_File.class.php + libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + updated copyright notice + + * libs/Smarty.class.php + libs/core/core.load_plugins.php: + fixed bug that occurred when using the same not-cacheable plugin in + multiple includes + + * docs/programmers.sgml: + docs-update for plugins.writing + +2003-08-04 Messju Mohr + + * docs/designers.sgml + docs/programmers.sgml: + updated docs for register_block_function(), block-functions, + $request_use_auto_globals and html_checkboxes + +2003-07-31 Messju Mohr + + * NEWS + libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + enabled registration of class-methods as callbacks for the + register_*-functions + + use: array('classname', 'method_name')) as callback + +2003-07-29 Messju Mohr + + * libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + modifiers are resolved at compile-time now. _run_mod_handler() is + still used for modifiers with map_array=true (== no preceeding '@') + + * libs/Smarty.class.php + libs/Smarty_Compiler.class.php + libs/core/core.smarty_include.php: + moved _smarty_include() back into Smarty.class.php + + * libs/Smarty.class.php + libs/core/core.load_plugins.php: + prevent unnecessary calls to _read_file() in _is_compiled() + converted method-call to internal function-call in + smarty_core_load_plugins() + +2003-07-28 Messju Mohr + + * libs/Smarty_Compiler.class.php: + quote smarty-header properly to prevent resource-names from escaping from + the comment + +2003-07-25 Messju Mohr + + * libs/core/core.create_dir_structure.php: + weakend race-condition and removed bogus error-message caused by that + in smarty_core_create_dir_structure(). + +2003-07-23 Messju Mohr + + * libs/Smarty.class.php + libs/core/core.display_debug_console.php + libs/core/core.fetch_resource_info.php + libs/core/core.get_php_resource.php + libs/core/core.parse_resource_name.php + libs/core/core.process_cached_inserts.php + libs/core/core.read_cache_file.php + libs/core/core.run_insert_handler.php + libs/core/core.smarty_include.php + libs/core/core.smarty_include_php.php + libs/plugins/function.eval.php: + moved _fetch_resource_info and _parse_resource_name back into + Smarty.class.php + renamed smarty_include and smarty_eval wrappers to _include and _eval + +2003-07-17 Messju Mohr + + * libs/core/core.process_compiled_include.php + libs/core/core.read_cache_file.php: + improved checking of compiled_include against cached-template with + non-cached-chunks + + * libs/core/core.write_compiled_include.php: + fixed too short open-tag + + * libs/plugins/function.eval.php: + fixed assign parameter for eval (must have gotton lost on its way to 2.5.0) + cleaned up indentiation + +2003-07-03 Messju Mohr + + * libs/Smarty_Compiler.class.php: + resurrected $foo->$bar syntax + + * libs/Smarty_Compiler.class.php: + i'm so stupid. kick me. + + * libs/Smarty_Compiler.class.php: + fixed initialisation of $this->_plugins in compile_block_tag() + +2003-07-03 Monte Ohrt + + * libs/Config_File.class.php: + add preg_quote delimiter + +2003-07-03 Messju Mohr + + * libs/Smarty_Compiler.class.php: + applied fix for {$var1->p1|modifier:$var2->p2}-syntax - thanks Dominik + +2003-07-02 Messju Mohr + + * libs/Smarty_Compiler.class.php: + fixed duplicate generation of arg-list in _compile_block_tag() + + * libs/Smarty_Compiler.class.php: + fixed off-by-one-error in nocache-tag-handling + +2003-06-30 Messju Mohr + + * libs/Smarty_Compiler.class.php: + backed out errornously committed support for $foo->$bar + + * libs/core/core.write_file.php: + fixed indentiation, silenced occasional warning + + * libs/plugins/function.html_image.php: + match first character of file-attribute against "/" instead of + DIRECTORY_SEPARATOR since it is a url-path and not a file-path. + + * libs/Smarty_Compiler.class.php + libs/core/core.write_file.php + libs/plugins/function.html_image.php: + libs/plugins/function.html_image.php + + * libs/Smarty_Compiler.class.php: + re-fixed cacheable_state-handling + + * libs/core/core.display_debug_console.php + libs/core/core.process_cached_inserts.php + libs/core/core.process_compiled_include.php + libs/core/core.run_insert_handler.php: + extincting $this out of smarty_core_*-functions + + * libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + fixed handling of nocache-state + +2003-06-29 Messju Mohr + + * libs/Smarty.class.php + libs/core/core.smarty_include.php + libs/core/core.smarty_include_php.php + libs/plugins/function.eval.php: + removed $this from smarty_include and smarty_include_php + added cleaner handling of $this to {eval} + + * libs/core/core.load_resource_plugin.php: + fixed inlude_once-call + + * docs/de/designers.sgml + docs/fr/designers.sgml: + fixed examples of html_radios and html_checkboxes in german and french docs + +2003-06-25 Monte Ohrt + + * libs/core/core.assemble_auto_filename.php + libs/core/core.write_cache_paths_file.php: + fix typo, fix write_cache_paths logic + + * libs/Smarty.class.php + libs/core/core.assemble_auto_filename.php: + fix SMARTY_COMPILE_DIR_SEP problem, make local var + +2003-06-24 Monte Ohrt + + * libs/Smarty.class.php + libs/core/core.assemble_auto_filename.php + libs/core/core.write_cache_paths_file.php: + fixed cache_paths bug, simplified filename assembly logic + +2003-06-24 Messju Mohr + + * libs/plugins/function.html_image.php: + added parsing of forgotton param "basedir" + + * libs/Smarty_Compiler.class.php: + fixed $smarty.get-reference + + * libs/plugins/block.textformat.php: + removed warning + + * libs/Smarty_Compiler.class.php: + fixed value of _cacheable_state on compiler-startup + +2003-06-23 Monte Ohrt + + * libs/Smarty.class.php + libs/Smarty_Compiler.class.php + libs/core/core.write_cache_paths_file.php: + make cache_path per resource, fix a couple directory path issues + +2003-06-23 Messju Mohr + + * libs/Smarty_Compiler.class.php: + removed warning when compiling empty template + + * libs/core/core.write_compiled_include.php: + fixed bug in write_compiled_include + + * libs/core/core.assemble_plugin_filepath.php: + fixed warning + +2003-06-22 Messju Mohr + + * libs/plugins/function.eval.php: + fixed propagation of $this into evald code in smarty_function_eval() + + * libs/core/core.write_cache_paths_file.php + libs/core/core.write_compiled_include.php: + fix in compiled-include-handling + + * libs/core/core.assemble_auto_filename.php + libs/core/core.assemble_plugin_filepath.php + libs/core/core.assign_smarty_interface.php + libs/core/core.create_dir_structure.php + libs/core/core.fetch_resource_info.php + libs/core/core.get_include_path.php + libs/core/core.get_microtime.php + libs/core/core.get_php_resource.php + libs/core/core.is_secure.php + libs/core/core.is_trusted.php + libs/core/core.load_plugins.php + libs/core/core.load_resource_plugin.php + libs/core/core.parse_resource_name.php + libs/core/core.read_cache_file.php + libs/core/core.rm_auto.php + libs/core/core.rmdir.php + libs/core/core.write_cache_file.php + libs/core/core.write_cache_paths_file.php + libs/core/core.write_compiled_include.php + libs/core/core.write_compiled_resource.php + libs/core/core.write_file.php + libs/plugins/modifier.date_format.php: + started moving from $this to $smarty in core.*.php + +2003-06-21 Monte Ohrt + + * libs/core/core.create_dir_structure.php + libs/core/core.write_file.php + libs/plugins/function.config_load.php: + fix more dir paths + + * NEWS + libs/Smarty.class.php + libs/core/core.assemble_auto_filename.php + libs/core/core.assemble_plugin_filepath.php + libs/core/core.fetch_resource_info.php + libs/core/core.get_php_resource.php + libs/core/core.parse_resource_name.php + libs/core/core.process_cached_inserts.php + libs/core/core.read_cache_file.php + libs/core/core.rm_auto.php + libs/core/core.rmdir.php + libs/core/core.run_insert_handler.php + libs/core/core.smarty_include.php + libs/core/core.smarty_include_php.php + libs/core/core.write_cache_file.php + libs/core/core.write_cache_paths_file.php + libs/core/core.write_compiled_include.php + libs/core/core.write_compiled_resource.php + libs/core/core.write_file.php + libs/plugins/function.config_load.php + libs/plugins/function.fetch.php + libs/plugins/function.html_image.php: + fix filepaths to core files to use DIRECTORY_SEPARATOR + +2003-06-21 Messju Mohr + + * libs/Smarty_Compiler.class.php: + fixed {plugin|modifier} syntax + + * libs/Smarty.class.php + libs/core/core.write_compiled_include.php: + fixed compiled include handling + +2003-06-21 Monte Ohrt + + * libs/Smarty.class.php + libs/Smarty_Compiler.class.php + libs/core/core.assemble_auto_filename.php + libs/core/core.assemble_plugin_filepath.php + libs/core/core.write_cache_paths_file.php: + added filepath caching + +2003-06-20 Monte Ohrt + + * libs/Smarty_Compiler.class.php: + update more varnames + + * libs/Smarty.class.php + libs/core/core.display_debug_console.php + libs/core/core.fetch_file_info.php + libs/core/core.fetch_resource_info.php + libs/core/core.get_php_resource.php + libs/core/core.parse_file_path.php + libs/core/core.parse_resource_name.php + libs/core/core.process_cached_inserts.php + libs/core/core.read_cache_file.php + libs/core/core.run_insert_handler.php + libs/core/core.smarty_include.php + libs/core/core.smarty_include_php.php + libs/core/core.write_compiled_resource.php + libs/core/core.write_compiled_template.php + libs/plugins/function.config_load.php: + refactored var naming to better reflect "resource" instead of "file" where + appropriate + +2003-06-19 Messju Mohr + + * libs/Smarty.class.php: + updated version-number to 2.5.0-cvs + + * libs/core/core.write_cache_file.php: + omit is-cache_dir-writable-check if a cache_handler_function is in use + + * libs/core/core.smarty_include_php.php: + fixed comments in smarty_include_php + +2003-06-19 Monte Ohrt + + * libs/Smarty.class.php + libs/Smarty_Compiler.class.php + libs/core/core.display_debug_console.php + libs/core/core.smarty_include.php + libs/plugins/function.eval.php: + split up _compile_template to _compile_file and _compile_source, fix eval + function + VS: ---------------------------------------------------------------------- + + * libs/plugins/function.config_load.php: + fix logic for _is_compiled() + +2003-06-19 Messju Mohr + + * NEWS + libs/Smarty_Compiler.class.php: + added optional assign-attribute to {capture}-tag + + * NEWS + libs/Smarty.class.php: + added $cacheable-parameter to register_compiler_function() + +2003-06-18 Messju Mohr + + * NEWS + libs/Smarty.class.php + libs/Smarty_Compiler.class.php + libs/core/core.load_plugins.php + libs/core/core.process_compiled_include.php + libs/core/core.read_cache_file.php + libs/core/core.write_cache_file.php + libs/core/core.write_compiled_include.php: + added $cacheable-parameter to register_function() and register_block() + + * libs/Smarty.class.php: + append '.php' to all compiled templates regardless of the settings of + $use_sub_dirs + + * libs/Smarty.class.php + libs/core/core.read_cache_file.php: + fixed $file_path-parameters passed to smarty_core_fetch_file_info() + +2003-06-17 Monte Ohrt + + * NEWS: + fix name + + * libs/Smarty_Compiler.class.php: + change varnames to follow coding methods + + * NEWS + libs/Smarty_Compiler.class.php: + add math patch to core + +2003-06-17 Messju Mohr + + * libs/core/core.smarty_include.php: + switched _process_template() to _is_compiled()-logic + +2003-06-17 Monte Ohrt + + * libs/Smarty.class.php: + fix _is_compiled logic + + * NEWS: + update news file + + * libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + fix _run_mod_handler routine + + * libs/Smarty.class.php + libs/Smarty_Compiler.class.php + libs/core/core.display_debug_console.php + libs/core/core.fetch_file_info.php + libs/core/core.parse_file_path.php + libs/core/core.write_compiled_template.php + libs/plugins/function.config_load.php: + fix path problems, rename some varibles from "template" to "file" + +2003-06-16 Monte Ohrt + + * libs/core/core.fetch_file_info.php + libs/core/core.fetch_template_info.php: + rename file, commit + + * libs/Smarty.class.php + libs/Smarty_Compiler.class.php + libs/core/core.parse_file_path.php + libs/core/core.read_cache_file.php + libs/plugins/block.strip.php + libs/plugins/block.textformat.php + libs/plugins/compiler.config_load.php + libs/plugins/function.config_load.php + libs/plugins/function.eval.php + libs/plugins/function.fetch.php + libs/plugins/function.html_image.php: + fix config_load, compile fetched arrays to compile_dir, switch display + back to runtime. clean up var names and function names, split up compile + testing and compiling to separate funcs, rename some template_* functions + to + file_* functions and update logic so they can be used for file resources + other than templates. + +2003-06-16 Messju Mohr + + * libs/Smarty_Compiler.class.php: + fixed little bug in _compile_custom_tag() + +2003-06-16 Monte Ohrt + + * NEWS + libs/Smarty.class.php + libs/Smarty_Compiler.class.php + libs/core/core.assign_smarty_interface.php + libs/core/core.create_dir_structure.php + libs/core/core.display_debug_console.php + libs/core/core.fetch_template_info.php + libs/core/core.get_include_path.php + libs/core/core.get_microtime.php + libs/core/core.get_php_resource.php + libs/core/core.is_secure.php + libs/core/core.is_trusted.php + libs/core/core.load_plugins.php + libs/core/core.load_resource_plugin.php + libs/core/core.parse_file_path.php + libs/core/core.process_cached_inserts.php + libs/core/core.read_cache_file.php + libs/core/core.rm_auto.php + libs/core/core.rmdir.php + libs/core/core.run_insert_handler.php + libs/core/core.smarty_include.php + libs/core/core.smarty_include_php.php + libs/core/core.write_cache_file.php + libs/core/core.write_compiled_template.php + libs/core/core.write_file.php + libs/plugins/core.assign_smarty_interface.php + libs/plugins/core.create_dir_structure.php + libs/plugins/core.display_debug_console.php + libs/plugins/core.fetch_template_info.php + libs/plugins/core.get_include_path.php + libs/plugins/core.get_microtime.php + libs/plugins/core.get_php_resource.php + libs/plugins/core.is_secure.php + libs/plugins/core.is_trusted.php + libs/plugins/core.load_plugins.php + libs/plugins/core.load_resource_plugin.php + libs/plugins/core.parse_file_path.php + libs/plugins/core.process_cached_inserts.php + libs/plugins/core.read_cache_file.php + libs/plugins/core.rm_auto.php + libs/plugins/core.rmdir.php + libs/plugins/core.run_insert_handler.php + libs/plugins/core.smarty_include.php + libs/plugins/core.smarty_include_php.php + libs/plugins/core.write_cache_file.php + libs/plugins/core.write_compiled_template.php + libs/plugins/core.write_file.php: + move core files into their own directory under SMARTY_DIR, + remove abstraction function _execute_core_function + + * libs/Smarty_Compiler.class.php: + fix newline handling for template for all template tags + +2003-06-11 Monte Ohrt + + * libs/plugins/compiler.config_load.php: + add compiler function to cvs repository + +2003-06-11 Messju Mohr + + * NEWS + libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + added config-option "request_use_auto_globals" to make auto-globals be + used as request vars instead of HTTP_*_VARS + +2003-06-11 Monte Ohrt + + * NEWS + libs/Smarty.class.php + libs/Smarty_Compiler.class.php + libs/plugins/function.config_load.php: + make config vars compile statically + +2003-06-11 Messju Mohr + + * NEWS + libs/Smarty_Compiler.class.php: + backed out newlines patch + + * NEWS + libs/Smarty_Compiler.class.php: + removed newlines in compiled templates after closing tags + +2003-06-10 Messju Mohr + + * docs/de/designers.sgml: + fixed german note on html_image and disk-access + +2003-06-10 Monte Ohrt + + * libs/plugins/core.parse_file_path.php: + fix bug with resource_type resolving + +2003-06-09 Monte Ohrt + + * docs/designers.sgml: + replace example with more practical one + +2003-06-08 Messju Mohr + + * NEWS + libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + added block-methods for registered objects + +2003-06-07 Messju Mohr + + * docs/programmers.sgml: + fixed bug in documentation for $smarty->default_modifiers + +2003-06-06 Monte Ohrt + + * libs/plugins/core.parse_file_path.php: + fix problem with new default_resource_type changes + + * NEWS: + update NEWS file info + + * NEWS + libs/Smarty.class.php + libs/plugins/core.parse_file_path.php: + add default_resource_type, ignore 1 char resource names + + * NEWS + libs/Config_File.class.php: + fix bug where config file starts with hidden section + +2003-06-04 Monte Ohrt + + * NEWS + libs/Smarty.class.php: + -** empty log message *** + +2003-06-03 Monte Ohrt + + * libs/plugins/function.html_image.php: + fix example in code comments + +2003-06-03 Messju Mohr + + * NEWS + libs/plugins/function.counter.php: + fixed behaviour of start=... for {counter} + +2003-06-02 Messju Mohr + + * NEWS + libs/plugins/function.counter.php: + fixed assign for {counter} + +2003-05-30 Monte Ohrt + + * libs/plugins/core.write_cache_file.php + libs/plugins/core.write_compiled_template.php: + add discrete error checking pertaining to $cache_dir + and $compile_dir, their existance and writability + +2003-05-28 Messju Mohr + + * NEWS + libs/plugins/function.html_table.php: + added params vdir, hdir and inner to html_table to allow looping over + the data in various directions + +2003-05-28 Monte Ohrt + + * libs/plugins/core.compile_template.php + libs/plugins/core.display_debug_console.php: + fix problem with security and debug.tpl file + +2003-05-23 Monte Ohrt + + * NEWS: + upd NEWS file + + * libs/Smarty_Compiler.class.php: + allow spaces in literal tags + +2003-05-22 Monte Ohrt + + * docs/fr/programmers.sgml: + fix special chars + +2003-05-19 Monte Ohrt + + * NEWS + libs/Smarty_Compiler.class.php: + speed up compiled templates, hardcode plugin filepaths instead of + recalculate at runtime + +2003-05-19 Messju Mohr + + * docs/designers.sgml: + fixed example of {html_image} + + * docs/designers.sgml: + fixed typo + +2003-05-12 Messju Mohr + + * libs/Smarty.class.php + libs/plugins/core.read_cache_file.php + libs/plugins/core.smarty_include.php + libs/plugins/function.config_load.php: + fixed multiple redundant occurrences for 'config' and 'template' in + $smarty->_cache_info + +2003-05-10 Messju Mohr + + * libs/plugins/core.create_dir_structure.php: + refurbished create_dir_structure to use '/' internally + + * libs/plugins/core.create_dir_structure.php: + fixed windows absolute-paths in smarty_core_create_dir_structure() + + * libs/plugins/core.create_dir_structure.php: + fixed error-message + +2003-05-09 Messju Mohr + + * libs/Smarty_Compiler.class.php: + fixed warning due to missing param to _execute_core_function() + + * libs/Smarty_Compiler.class.php: + fixed quoting in _compile_include_php + + * libs/Smarty_Compiler.class.php: + fixed quoting of "file"-parameter in _compile_include_tag() + +2003-05-08 Monte Ohrt + + * docs/programmers.sgml: + fix typo + + * libs/Smarty.class.php + libs/Smarty_Compiler.class.php + libs/plugins/core.compile_template.php + libs/plugins/core.create_dir_structure.php + libs/plugins/core.fetch_template_info.php + libs/plugins/core.get_include_path.php + libs/plugins/core.get_microtime.php + libs/plugins/core.get_php_resource.php + libs/plugins/core.is_secure.php + libs/plugins/core.is_trusted.php + libs/plugins/core.load_plugins.php + libs/plugins/core.load_resource_plugin.php + libs/plugins/core.parse_file_path.php + libs/plugins/core.process_cached_inserts.php + libs/plugins/core.read_cache_file.php + libs/plugins/core.rm_auto.php + libs/plugins/core.rmdir.php + libs/plugins/core.run_insert_handler.php + libs/plugins/core.smarty_include.php + libs/plugins/core.smarty_include_php.php + libs/plugins/core.write_cache_file.php + libs/plugins/core.write_compiled_template.php + libs/plugins/core.write_file.php + libs/plugins/function.config_load.php + libs/plugins/function.fetch.php + libs/plugins/function.html_image.php: + abstract more private functions to plugin directory + + * libs/Config_File.class.php: + only add DIRECTORY_SEPARATOR if it isn't already present + + * libs/Config_File.class.php: + fix directory separator code, use DIRECTORY_SEPARATOR + +2003-05-08 Messju Mohr + + * docs/designers.sgml: + fixed example of html_checkboxes + + * NEWS + libs/Smarty.class.php: + fixed bug in _create_dir_structure() when used with + open_basedir-restriction and relative paths + + * docs/designers.sgml: + fixed example for html_radios + +2003-05-07 Monte Ohrt + + * libs/Smarty.class.php + libs/Smarty_Compiler.class.php + libs/plugins/core.assign_smarty_interface.php + libs/plugins/core.display_debug_console.php + libs/plugins/function.display_debug_console.php: + abstracted display_debug_console and assign_smarty_interface to plugin dir + as a test + + * libs/Smarty.class.php + libs/plugins/function.display_debug_console.php: + correct misc varnames, abstract debug console display to plugin function + + * libs/plugins/modifier.escape.php: + fix typo + +2003-05-05 Monte Ohrt + + * libs/Smarty_Compiler.class.php: + add % to math + + * libs/Smarty.class.php: + clean up comments, formatting + + * NEWS + libs/Smarty.class.php: + keep DIR_SEP for 3rd party compatability + + * NEWS + libs/Smarty.class.php: + remove DIR_SEP, use DIRECTORY_SEPARATOR exclusively + + * libs/Smarty_Compiler.class.php: + remove ++ and -- math operators on template vars + +2003-05-04 Messju Mohr + + * libs/Smarty_Compiler.class.php: + removed unused parameter $quote from Smarty_Compiler::_parse_attrs() + + * libs/plugins/function.html_image.php: + fixed DIR_SEP in html_image-plugin + +2003-05-04 Monte Ohrt + + * NEWS + libs/Smarty.class.php: + rename DIR_SEP to SMARTY_DIR_SEP to avoid varname collisions + +2003-05-04 Messju Mohr + + * NEWS + libs/plugins/function.html_image.php: + changed "link" to "href" in html_image. "link" is still working but + deprecated + html_image always renders an alt-tag now (default alt="") + cleaned up indentiation of function.html_image.php + +2003-05-03 Monte Ohrt + + * libs/debug.tpl: + fix typo + +2003-05-02 Messju Mohr + + * NEWS + libs/plugins/function.counter.php: + fixed assign attribute for multiple counters + +2003-05-02 Monte Ohrt + + * libs/Smarty_Compiler.class.php: + allow math on negative number + + * NEWS + libs/Smarty_Compiler.class.php: + added simple math operators to variables + +2003-05-02 Messju Mohr + + * docs/designers.sgml: + fixed typos + +2003-04-30 Monte Ohrt + + * docs/fr/appendixes.sgml + docs/fr/common.dsl + docs/fr/designers.sgml + docs/fr/getting-started.sgml + docs/fr/html-common.dsl + docs/fr/html.dsl + docs/fr/manual.sgml + docs/fr/php.dsl + docs/fr/preface.sgml + docs/fr/programmers.sgml: + add frech docs to cvs repository + +2003-04-29 Messju Mohr + + * NEWS + libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + reverted patch for case-insensitive tag-names + +2003-04-28 Messju Mohr + + * docs/programmers.sgml: + reverted back to humerous redundancy in the docs :). although we all + know we are here to generate template-based output, and not to have + fun ;-) + + * docs/getting-started.sgml: + fixed default user and group for max os x installation + + * libs/Smarty.class.php: + made $function[2] and $function[3] options for register_resource + + * libs/Smarty.class.php: + fixed issue with object-callback when fetching a php-resource + + * NEWS + libs/Smarty.class.php: + enabled array(&$obj. 'source', 'timestamp', 'secure', 'trusted') as + callback for register_resource() + + enabled array(&$obj, 'method') as callback for + $default_template_handler_func + +2003-04-27 Messju Mohr + + * docs/designers.sgml + docs/programmers.sgml: + fixed some typos, thank to mehdi + + * libs/plugins/function.counter.php: + prevent assign from overruling print-attribute in function.counter.php + + * libs/plugins/function.counter.php: + fixed problem with counter and assign + + * libs/Smarty.class.php: + fixed notice in _load_plugins() + + * NEWS + libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + made plugin-names case-insensitive. this affects + compiler/block/custom-functions and modifers. + +2003-04-26 Monte Ohrt + + * NEWS + libs/Smarty_Compiler.class.php: + remove unnecessary close/open tags from compiled templates + +2003-04-26 Messju Mohr + + * docs/designers.sgml: + added documentation for foreach.property.* + +2003-04-24 Messju Mohr + + * docs/designers.sgml: + fixed example table_attr and tr_attr in html_table-example + +2003-04-21 Greg Beaver + + * libs/Smarty.class.php: + fixed small bug in doc comments + +2003-04-21 Messju Mohr + + * NEWS + libs/plugins/function.html_image.php: + fixed errornous creation of '//' in image_path in html_image + +2003-04-21 Monte Ohrt + + * libs/plugins/modifier.debug_print_var.php: + fix htmlspecialchars() conflict + + * NEWS + libs/plugins/modifier.debug_print_var.php: + fix escapement of special chars in key values of debug console + + * NEWS + libs/plugins/function.config_load.php: + fixed debug timing logic for config_load + + * docs/designers.sgml: + fix example text + + +2003-04-20 Greg Beaver + * plugins/* + Smarty.class.php + Smarty_Compiler.class.php + Config_File.class.php: + updated all doc comments to phpDocumentor format (whew!) + +2003-04-06 Messju Mohr + + * libs/plugins/function.math.php: + allowed "_" in the name of variable-parameters to {math}-function + +2003-04-04 Monte Ohrt + + * NEWS + docs/designers.sgml + libs/Smarty_Compiler.class.php: + change backtic syntax from $`foo` to `$foo` + + * NEWS + libs/Smarty_Compiler.class.php: + recognize $foo[][] syntax in embedded quotes without backticks + +2003-04-03 Messju Mohr + + * NEWS + libs/Smarty_Compiler.class.php: + name=123 is passed as an integer (not a string) to plugins now + +2003-04-01 Messju Mohr + + * libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + added CVS $Id: ChangeLog,v 1.1 2005/10/17 18:37:38 jeichorn Exp $ + +2003-03-31 Messju Mohr + + * libs/Smarty.class.php: + added missing compile_id inside Smarty_Compiler + + * libs/Smarty_Compiler.class.php: + fixed flaw when generating an error for missing postfilter + +2003-03-31 Monte Ohrt + + * docs/getting-started.sgml + docs/programmers.sgml: + fix typos + +2003-03-27 Messju Mohr + + * NEWS + libs/plugins/modifier.debug_print_var.php: + $length is now propagated to sub-values in debug_print_var + +2003-03-26 Monte Ohrt + + * NEWS: + update header + + * RELEASE_NOTES: + commit changes to release notes + + * (Smarty_2_5_0_RC2) + libs/Config_File.class.php + libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + committing RC2 + +2003-03-24 Messju Mohr + + * NEWS + libs/Smarty.class.php: + made clear_cache() ignore compile_id when clearing cache_groups + + * libs/plugins/function.popup.php: + made onmouseout XHTML-compatible in function.popup.php + +2003-03-21 Messju Mohr + + * NEWS + libs/Smarty.class.php: + applied new var-names to fetch() + + * NEWS + libs/Smarty.class.php: + renamed $localvars to $_localvars in cache-file-handling-functions, + added _get_auto_id()-function + +2003-03-21 Monte Ohrt + + * libs/plugins/function.mailto.php + libs/plugins/function.popup.php: + update functions for XHTML compatability + +2003-03-21 Messju Mohr + + * libs/Smarty.class.php: + fixed wrong $auto_id in _read_cache_file() + + * NEWS + libs/Smarty.class.php: + swapped compile_id and cache_id in read_cache_file and write_cache_file + + * libs/Smarty.class.php: + reverted patch for ignoring compile-id back to -r1.364, due to problems + + * NEWS + libs/plugins/function.html_checkboxes.php + libs/plugins/function.html_radios.php: + html_radios and html_checkboxes accept "selected" instead of "checked" + optionally now + + * NEWS + libs/Smarty.class.php: + swapped compile_id and cache_id for cache-file-handling again + +2003-03-20 Monte Ohrt + + * libs/Smarty_Compiler.class.php: + fix notice when no parameter is passed to default + +2003-03-20 Messju Mohr + + * NEWS + libs/Smarty.class.php: + removed notice of undefined var in _rm_auto() + +2003-03-19 Monte Ohrt + + * libs/plugins/function.html_checkboxes.php + libs/plugins/function.html_radios.php + libs/plugins/function.html_table.php: + fix a few error messages, follow consistancy format plugin_name: errormsg + + * libs/plugins/function.html_radios.php: + update error messages + + * NEWS + libs/plugins/function.html_radios.php: + add a warning when an array is passed as the 'checked' value of html_radios + +2003-03-19 Messju Mohr + + * NEWS + libs/Smarty_Compiler.class.php: + fixed errormessage in _compile_smarty_ref() + + * NEWS + docs/designers.sgml: + updated docs for html_image + +2003-03-18 Messju Mohr + + * NEWS + libs/Smarty.class.php: + cleaned up calls to readdir() + + * libs/plugins/function.html_options.php: + fixed label for optgroup in html_options + +2003-03-18 Monte Ohrt + + * NEWS + libs/Smarty_Compiler.class.php: + fix (newly introduced) bug with passing multiple modifiers to a parameter + +2003-03-18 Messju Mohr + + * NEWS + docs/designers.sgml: + updated docs for html_checkboxes, html_options and html_radios + + * libs/plugins/function.html_options.php: + fixed wrong default-"name" in function.html_options.php + + * NEWS + libs/plugins/function.html_checkboxes.php + libs/plugins/function.html_radios.php: + renamed "checkbox" and "radios" to "options" in {html_checkboxes} and + {html_radios} + + * libs/plugins/outputfilter.trimwhitespace.php: + tried to optimize re-replacement in outputfilter.trimwhitespace.php a + little + + * libs/plugins/outputfilter.trimwhitespace.php: + fixed greedy str_replace in outputfilter.trimwhitespace.php + + * NEWS + libs/plugins/function.html_checkboxes.php + libs/plugins/function.html_options.php + libs/plugins/function.html_radios.php: + html_options, html_checkboxes and html_radios now pass-thru all unknown + paramters + +2003-03-17 Messju Mohr + + * NEWS + libs/plugins/function.html_options.php: + html_options passthru all unknown paramters now + +2003-03-17 Monte Ohrt + + * NEWS + libs/plugins/function.html_image.php: + Fix link bug in html_image function, also make output XHTML compatible + + * libs/Smarty_Compiler.class.php: + fix issue of embedded var and escaped double quotes + +2003-03-15 Monte Ohrt + + * NEWS + libs/Smarty_Compiler.class.php: + back out "@" logic, apply only to default modifier special case + + * libs/Smarty_Compiler.class.php: + fix @ logic, only use upon an echo + + * NEWS + libs/Smarty_Compiler.class.php: + append "@" to template var echoes to supress possible notices + + * NEWS + libs/Smarty_Compiler.class.php: + append "@" to _run_mod_handler to supress warnings + +2003-03-14 Monte Ohrt + + * NEWS + libs/Smarty_Compiler.class.php: + fix problem with escaped double quotes + + * NEWS + libs/plugins/function.html_radios.php: + fixed html_options to not return an array + +2003-03-12 Messju Mohr + + * NEWS + libs/plugins/modifier.truncate.php: + fixed length in modifier.truncate.php + + * NEWS + libs/plugins/outputfilter.trimwhitespace.php: + fixed handling of '$'-signs in trimwhitespace outputfilter (messju) + +2003-03-12 Monte Ohrt + + * docs/programmers.sgml: + update technical explanation of assign_by_ref and append_by_ref + +2003-03-11 Monte Ohrt + + * NEWS + libs/Smarty.class.php: + fix config file recompiling code + +2003-03-07 Monte Ohrt + + * libs/plugins/function.html_image.php: + change E_USER_ERROR to E_USER_NOTICE + + * libs/plugins/function.html_image.php: + suppress warning in html_image + + * NEWS + libs/plugins/function.html_image.php: + update changes to html_image + +2003-03-06 Monte Ohrt + + * docs/designers.sgml + docs/de/appendixes.sgml + docs/de/common.dsl + docs/de/designers.sgml + docs/de/getting-started.sgml + docs/de/html-common.dsl + docs/de/html.dsl + docs/de/manual.sgml + docs/de/preface.sgml + docs/de/programmers.sgml: + add german docs to dist + + * NEWS: + update news file + + * libs/plugins/function.html_image.php: + fix width/height parameter index + + * NEWS + libs/Smarty.class.php: + get rid of unsetting name and script attributes to insert tags + +2003-03-05 Monte Ohrt + + * NEWS + RELEASE_NOTES: + update NEWS file + + * libs/plugins/modifier.string_format.php: + fix argument order, erroneously swapped a while back + + * (Smarty_2_5_0_RC1) + NEWS + README + RELEASE_NOTES + libs/Config_File.class.php + libs/Smarty.class.php + libs/Smarty_Compiler.class.php: + commit final changes for 2.5.0-RC1 + +2003-03-04 Monte Ohrt + + * docs/programmers.sgml: + remove $show_info_header and $show_info_include property vars from docs + +2003-03-03 Monte Ohrt + + * NEWS + libs/plugins/function.popup.php: + fixed PHP notice + +2003-02-28 Monte Ohrt + + * libs/Smarty_Compiler.class.php: + simplify smarty.const.foo and smarty.const.$foo logic + + * libs/Smarty_Compiler.class.php: + only allow $foo syntax in embedded quotes, unless escaped with backticks + then allow any dollar var + + * NEWS + libs/Smarty_Compiler.class.php: + fix "once" var compiling to work with new attr compiling methods for + include_php + + * FAQ + NEWS + README + docs/designers.sgml + docs/getting-started.sgml + libs/Smarty_Compiler.class.php + libs/plugins/function.html_checkboxes.php + libs/plugins/function.html_image.php + libs/plugins/function.html_options.php + libs/plugins/function.html_radios.php + libs/plugins/function.html_select_date.php + libs/plugins/function.html_select_time.php + libs/plugins/function.html_table.php: + fix $smarty.const.foo compiling, clean up double quoted strings, + allow full dollar var syntax in quotes again + +2003-02-27 Monte Ohrt + + * docs/designers.sgml + docs/programmers.sgml + libs/Smarty_Compiler.class.php: + update docs, fix smarty var compiling, allow any $smarty.*.$foo syntax, + add $`foobar` for embedded variables + + * libs/plugins/function.html_image.php: + update functionality + +2003-02-26 Monte Ohrt + + * NEWS + libs/plugins/modifier.nl2br.php: + add nl2br modifier + + * libs/plugins/function.html_image.php: + add link parameter + +2003-02-24 Monte Ohrt + + * libs/Smarty.class.php + libs/plugins/function.html_image.php: + fix rename problem in windows, unlink first + + * libs/plugins/function.html_checkboxes.php + libs/plugins/function.html_image.php + libs/plugins/function.html_options.php + libs/plugins/function.html_radios.php + libs/plugins/shared.escape_special_chars.php: + update functions with separate escape_special_chars routine + + * NEWS + libs/plugins/function.html_checkboxes.php + libs/plugins/function.html_radios.php: + commit checkboxes, update radios + + * NEWS + libs/Smarty.class.php + libs/plugins/function.html_image.php: + fix bug with get_registered_object + + * NEWS + libs/plugins/modifier.cat.php: + added cat modifier to distribution + + * NEWS + libs/Smarty_Compiler.class.php: + added << >> <> support to IF statements + + * libs/plugins/function.html_radios.php: + apply patch to initial html_radios function + + * NEWS + libs/Smarty.class.php: + fix _assign_smarty_interface to not overwrite keys other than 'request' + + * NEWS + libs/plugins/function.html_radios.php: + added html_radios to distribution + + * NEWS + libs/plugins/modifier.string_format.php: + fixed arg order of string_format + + * NEWS + libs/Smarty.class.php: + use tmp file for file writes, avoid race condition + + * NEWS + libs/Smarty_Compiler.class.php: + add $smarty.config.foo var, handle embedded smarty var correctly + + * NEWS + libs/plugins/function.fetch.php: + silence warnings in fetch plugin + +2003-02-21 Monte Ohrt + + * INSTALL: + update wording + + * INSTALL: + update install instructions + + * AUTHORS + BUGS + CREDITS + QUICKSTART + README + RESOURCES + TESTIMONIALS: + remove some files already in docs or elsewhere + + * demo/index.php: + add templates_c to repository + + * index.php: + move demo files to demo directory + + * Config_File.class.php + Smarty.class.php + Smarty_Compiler.class.php + debug.tpl: + moved lib files under libs directory + +2003-02-20 Monte Ohrt + + * NEWS + Smarty.class.php: + add get_config_vars() method, update get_template_vars() functionality + + * NEWS + Smarty.class.php: + fix minor logic in _fetch_template_info() + + * NEWS + Smarty.class.php: + support merging appended vars + + * NEWS + Smarty.class.php: + fix cache groups behavior with compile_id set + +2003-02-19 Monte Ohrt + + * Smarty.class.php: + back out third parameter, extend functionality of append + + * NEWS + Smarty_Compiler.class.php: + update imbedded vars, allow special $smarty vars + + * plugins/function.html_table.php: + add plugin html_table + + * NEWS + Smarty.class.php: + support appending key=>val pairs + + * NEWS + Smarty_Compiler.class.php: + change embedded variable logic to only recognize $foo and $foo[0][bar] + syntax + + * NEWS + Smarty_Compiler.class.php: + allow null as function attribute value + +2003-02-18 Monte Ohrt + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php: + support foo->bar[index] syntax + + * Smarty_Compiler.class.php: + allow $foo->bar[0] syntax + +2003-02-17 Monte Ohrt + + * plugins/modifier.escape.php: + fix syntax error from previous commit + + * NEWS + Smarty.class.php: + add error msgs to get_registered_object + + * Smarty.class.php: + add function for getting reference to registered object + + * Smarty_Compiler.class.php: + back out patches for object and objref calls on $smarty var + + * NEWS + Smarty_Compiler.class.php: + treat unrecognized param attribute syntax as a string + + * NEWS + Smarty_Compiler.class.php: + support $smarty.const.$foo syntax + + * NEWS + debug.tpl + plugins/modifier.count_words.php + plugins/modifier.escape.php: + fix E_NOTICE messages + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php: + add @ and === to if tokens, few param cleanups + +2003-02-16 Greg Beaver + + * ChangeLog + Smarty.class.php + Smarty_Compiler.class.php: + many more phpdoc comment upgrades + +2003-02-15 Greg Beaver + * Smarty.class.php + Smarty_Compiler.class.php + continue cleaning of phpdoc comments. All that is needed is the + addition of @return tags and perhaps a bit more verbose comments + and they are finished. + +2003-02-14 Monte Ohrt + + * NEWS + Smarty.class.php: + enable config_load error messages + + * NEWS + plugins/function.html_options.php: + fix html_options to not escape already escaped entities + + * NEWS + Smarty.class.php: + send Last-Modified header on cache creation, misc tab/spacing cleanup + +2003-02-13 Monte Ohrt + + * Smarty_Compiler.class.php + docs/designers.sgml: + allow dash in plain text + + * NEWS + Smarty_Compiler.class.php: + check strict syntax of function attributes + +2003-02-12 Monte Ohrt + + * NEWS + Smarty_Compiler.class.php: + dropped support for modifiers on object parameters, + added support for objects as modifier parameters + + * NEWS + Smarty_Compiler.class.php + docs/designers.sgml: + fix bug with decimal numbers in if statements, misc doc updates + +2003-02-11 Monte Ohrt + + * (Smarty_2_4_2) + Config_File.class.php + NEWS + README + RELEASE_NOTES + Smarty.class.php + Smarty_Compiler.class.php: + update version numbers + +2003-02-10 Monte Ohrt + + * NEWS + Smarty_Compiler.class.php: + add support for $foo->$bar syntax + + * NEWS: + update NEWS file + + * NEWS + Smarty_Compiler.class.php: + support full var syntax in quoted text, fix problem with const var access, + clean up some more regex code, fix object problem with no properties + +2003-02-06 Monte Ohrt + + * (Smarty_2_4_1) + Config_File.class.php + NEWS + README + RELEASE_NOTES + Smarty.class.php + Smarty_Compiler.class.php: + committed 2.4.1 changes + + * NEWS + Smarty_Compiler.class.php: + ignore case in IF statements + +2003-02-05 Monte Ohrt + + * NEWS + Smarty_Compiler.class.php: + treat undefined constants as null + + * NEWS + Smarty.class.php: + fix problem with inserts and nested fetches + + * Smarty_Compiler.class.php: + fix "if" regex for math tokens + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php + docs/getting-started.sgml: + added support for extracting params to include_php + +2003-02-04 Monte Ohrt + + * RELEASE_NOTES: + reformat text + +2003-02-03 Monte Ohrt + + * NEWS: + update news file + +2003-02-03 Greg Beaver + + * ChangeLog + Smarty.class.php: + begin fixing phpdoc comments in Smarty.class.php + + * ChangeLog + Config_File.class.php: + fixed phpdoc comments + +2003-02-03 Monte Ohrt + + * Smarty_Compiler.class.php: + allow $foo->bar[$x].foo syntax + + * Smarty_Compiler.class.php + index.php + configs/test.conf + templates/index.tpl: + fix accidental commit + + * index.php + configs/test.conf + templates/index.tpl: + allow $foo->bar[$j].blah type of syntax + +2003-02-02 Greg Beaver + + * Smarty.class.php + begin fixing of phpdoc comments + + * Config_File.class.php + fix phpdoc comments, add phpDocumentor docblock templates + +2003-02-02 Monte Ohrt + + * Smarty.class.php + docs/html.dsl + docs/php.dsl: + fix version number + + * (Smarty_2_4_0) + Config_File.class.php + NEWS + README + RELEASE_NOTES + Smarty.class.php + Smarty_Compiler.class.php + docs/appendixes.sgml + docs/designers.sgml + docs/programmers.sgml: + update Smarty version numbers + +2003-01-30 Monte Ohrt + + * NEWS + Smarty_Compiler.class.php + TODO: + fix order of php tag comparisons + + * NEWS + Smarty_Compiler.class.php: + fix known php tag handling problems + +2003-01-29 Monte Ohrt + + * Smarty.class.php + Smarty_Compiler.class.php: + change comments to phpdoc style + +2003-01-28 Monte Ohrt + + * Smarty.class.php + docs/programmers.sgml: + make separate var for compiler file + + * plugins/function.fetch.php: + fix error call + +2003-01-25 Monte Ohrt + + * Smarty.class.php + Smarty_Compiler.class.php: + add support for restriction to registered methods + + * plugins/outputfilter.trimwhitespace.php: + update with textarea support + +2003-01-24 Monte Ohrt + + * Smarty_Compiler.class.php: + fix compiling problem with {foreach} tags + + * Smarty.class.php + Smarty_Compiler.class.php: + put objects in own array, add object param format support, change + object syntax from foo.bar to foo->bar + +2003-01-23 Monte Ohrt + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php: + add support for object registration + +2003-01-22 Monte Ohrt + + * Smarty.class.php: + add file & line number of calling error to error message + +2003-01-21 Monte Ohrt + + * Smarty_Compiler.class.php: + put php style object syntax back in + +2003-01-20 Monte Ohrt + + * Smarty.class.php: + move security settings to fetch function for template_dir + + * NEWS + Smarty.class.php: + fix debug template and security, add template_dir to secure_dir at runtime + +2003-01-17 Monte Ohrt + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php: + added new object support without new template syntax + +2003-01-15 Monte Ohrt + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php: + fix if statement syntax for negative integers, fix issue with directories + named '0' + +2003-01-08 Monte Ohrt + + * Smarty.class.php + plugins/function.counter.php + plugins/function.cycle.php + plugins/function.debug.php + plugins/function.eval.php + plugins/function.fetch.php + plugins/function.html_options.php + plugins/function.html_select_date.php + plugins/function.html_select_time.php + plugins/function.mailto.php + plugins/function.math.php + plugins/function.popup.php + plugins/function.popup_init.php: + update plugins to return values instead of echo, fix config file cache + to include global config variables in cache file + + * Smarty_Compiler.class.php: + fix bug with >= tests in if statements, comment out full object support + +2003-01-06 Monte Ohrt + + * NEWS + docs/html.dsl + plugins/modifier.escape.php: + add javascript escape parameter to escape modifier + +2003-01-02 Monte Ohrt + + * templates/header.tpl: + move the title into head where it should be + +2002-12-24 Monte Ohrt + + * Smarty_Compiler.class.php: + added correct line numbers to smarty syntax error messages + + * docs/programmers.sgml: + update append documentation, make more clear on its function + + * Smarty_Compiler.class.php: + fix modifier matching regexp + +2002-12-23 Monte Ohrt + + * Smarty_Compiler.class.php: + support nested function calls in IF statements + +2002-12-20 Monte Ohrt + + * Smarty_Compiler.class.php: + few more fixes, spaces around function parameters + + * Smarty_Compiler.class.php: + fix misc syntax issues with {if} tags + +2002-12-20 Monte Ohrt + + * Smarty_Compiler.class.php: + fix misc syntax issues with {if} tags + +2002-12-19 Monte Ohrt + + * Smarty_Compiler.class.php: + commit updates, passes all smoke tests + + * NEWS: + update NEWS file + + * Smarty_Compiler.class.php: + fixed literal string not in quotes as parameters + + * NEWS + Smarty_Compiler.class.php: + fix misc syntax issues, add ability to pass modifiers to functions + +2002-12-18 Monte Ohrt + + * NEWS: + update NEWS + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php: + update compiler code, clean up regex, add new syntax features + +2002-12-16 Monte Ohrt + + * NEWS: + update NEWS file + + * Smarty_Compiler.class.php: + commit updates for objects + +2002-12-14 Monte Ohrt + + * Smarty.class.php + Smarty_Compiler.class.php: + fix bug with compiling config files with caching on + +2002-12-13 Monte Ohrt + + * Smarty_Compiler.class.php: + fix problem with matching single quoted strings + + * Smarty_Compiler.class.php: + update embedded variable logic, get rid of ."" at end of output + + * NEWS + docs/designers.sgml + plugins/function.html_select_date.php: + add day_value_format to html_select_date + +2002-12-12 Monte Ohrt + + * plugins/modifier.debug_print_var.php: + fix bug, double escaped values in display + + * Smarty.class.php: + move debug test back into fetch() + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php + plugins/outputfilter.trimwhitespace.php: + assigned vars are no longer in global name space, few debug cleanups + +2002-12-11 Monte Ohrt + + * plugins/function.popup.php: + fix error in newline code + + * plugins/function.popup.php: + fix popup to allow newlines in text data + +2002-12-10 Monte Ohrt + + * Smarty.class.php: + fix plugin error logic + + * docs/designers.sgml + docs/programmers.sgml: + edit examples, make more verbose + + * NEWS + plugins/function.html_options.php: + escape html entities in the option values and output + + * NEWS + plugins/function.html_options.php: + fixed bug with label of html_options + +2002-12-09 Monte Ohrt + + * Smarty.class.php: + add support for var_export() + + * Config_File.class.php + Smarty.class.php: + clean up code, respect force_compile and compile_check flags + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php + docs/designers.sgml + plugins/function.mailto.php: + add caching feature to config loading, document update, add mailto plugin + +2002-12-08 Monte Ohrt + + * plugins/function.fetch.php: + fix query part of URL + +2002-12-05 Monte Ohrt + + * docs/designers.sgml: + fix typos + +2002-11-22 Monte Ohrt + + * Smarty_Compiler.class.php: + patch for warning message + +2002-11-21 Monte Ohrt + + * RELEASE_NOTES + Smarty.class.php: + get rid of testing for a set value with assign function, just set to + whatever is passed into the template + + * docs/programmers.sgml: + fix typo + +2002-11-19 Monte Ohrt + + * Config_File.class.php + NEWS + README + RELEASE_NOTES + Smarty.class.php + Smarty_Compiler.class.php: + commit changes, ready for 2.3.1 release + +2002-11-01 Monte Ohrt + + * plugins/function.html_options.php: + added label attribute to all option outputs, cover w3c spec. + + * NEWS: update NEWS file + + * docs/designers.sgml: update docs for optgroup output + + * plugins/function.html_options.php: + make html_options work with optgroup, make func modular and recursive. + +2002-10-29 Monte Ohrt + + * NEWS + Smarty.class.php: set mtime on compile files so they match source files + +2002-10-18 Monte Ohrt + + * NEWS + Smarty.class.php: added proper support for open_basedir setting + + * docs/designers.sgml: clear up docs on index, iteration and rownum + +2002-10-16 Monte Ohrt + + * plugins/modifier.default.php: fix warning message in default modifier + +2002-09-25 Monte Ohrt + + * docs/designers.sgml + plugins/modifier.strip.php + NEWS: added strip variable modifier + +2002-09-24 Andrei Zmievski + + * NEWS: *** empty log message *** + + * Smarty_Compiler.class.php: + Fix to be able to use $smarty.x variables as arrays. + +2002-09-23 Monte Ohrt + + * Config_File.class.php: + add support for mac/dos formatted config files (fix newlines) + + * docs/programmers.sgml: add optional tags to clear_cache parameters + + * docs/designers.sgml: + fix error with include_php description, add $this to description + +2002-09-20 Monte Ohrt + + * NEWS + docs/getting-started.sgml: fixed errors with example setup docs + +2002-09-16 Monte Ohrt + + * plugins/block.textformat.php + docs/designers.sgml + NEWS: add textformat block function + +2002-09-10 Monte Ohrt + + * docs/designers.sgml: + add assign attribute to cycle function documentation + + * docs/designers.sgml + docs/programmers.sgml: fix typos + +2002-09-09 Monte Ohrt + + * plugins/function.debug.php + templates/header.tpl: + fix header in debug template, fix typo in header.tpl example + +2002-08-15 mohrt + + * docs/programmers.sgml: fix typos + +2002-08-08 mohrt + + * RELEASE_NOTES + Smarty.class.php: + supress warnings from unlink() and is_dir(), let error handler deal with it + +2002-08-07 mohrt + + * docs/appendixes.sgml + docs/designers.sgml + docs/programmers.sgml + Config_File.class.php + NEWS + README + RELEASE_NOTES + Smarty.class.php + Smarty_Compiler.class.php: update files with new version numbers + +2002-08-02 mohrt + + * NEWS: update NEWS file with credits + + * NEWS + Smarty.class.php: added assign_by_ref() and append_by_ref() functions + +2002-08-01 mohrt + + * TODO + NEWS + Smarty.class.php: + changed default warning type for plugin errors from E_USER_WARNING to E_USER_ERROR + +2002-07-29 mohrt + + * plugins/function.html_select_time.php + docs/designers.sgml + NEWS: added paramters to html_select_time plugin + +2002-07-25 Andrei Zmievski + + * TODO: *** empty log message *** + +2002-07-24 mohrt + + * QUICKSTART: update QUICKSTART guide + + * NEWS + debug.tpl + plugins/modifier.debug_print_var.php: + update debug console to show objects, fix warning in debug.tpl + +2002-07-23 mohrt + + * docs/programmers.sgml: fix load_filter examples + + * Config_File.class.php + NEWS: fix error when there are no sections in config file + +2002-07-19 mohrt + + * docs/getting-started.sgml: fix error in install guide + +2002-07-18 mohrt + + * Smarty_Compiler.class.php: + correct the expression match for smarty:nodefaults + +2002-07-17 mohrt + + * Smarty_Compiler.class.php: fix default modifier to work with config vars + + * Smarty_Compiler.class.php: got args to strstr backwards... + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php: + change default modifiers to array instead of string + + * Smarty_Compiler.class.php + docs/designers.sgml + Smarty.class.php: add default modifier logic, minor doc updates + + * NEWS + Smarty.class.php + plugins/function.popup_init.php: + make popup_init xhtml compliant, minor variable name changes for consistancy + +2002-07-16 mohrt + + * NEWS: update NEWS file + + * plugins/function.debug.php + Smarty.class.php + debug.tpl + NEWS: + fix problem with filenames on windows, add ability to supply expire time in seconds when clearing cache or compiled files + +2002-07-15 mohrt + + * Smarty.class.php: + fixed problem with insert tags when loading function from script attribute + and caching enabled (Monte) + +2002-07-14 mohrt + + * NEWS + Smarty.class.php: fix bug with debug_tpl file path for Windows + +2002-07-12 Monte Ohrt + + * Smarty.class.php: fix append function with array/string issue + +2002-07-11 Monte Ohrt + + * RELEASE_NOTES: update release notes + + * NEWS + README + RELEASE_NOTES + Smarty.class.php + Smarty_Compiler.class.php + Config_File.class.php: update files to 2.2.0 tags, get ready for release + +2002-07-09 Monte Ohrt + + * NEWS + Smarty.class.php: make debug.tpl work with any delimiter + + * NEWS + Smarty.class.php: + change tests in append and assign to != '' instead of empty(), which is more accurate + +2002-07-08 Monte Ohrt + + * docs/designers.sgml: minor doc update + + * Smarty.class.php: + cast var as an array, simplify and get rid of PHP warning messages + +2002-07-03 Monte Ohrt + + * Smarty.class.php: one more N + + * Smarty.class.php: + prepend "N" to filenames to avoid possible OS issues with dir names starting with "-" + + * Smarty.class.php: only set $debug_tpl in constructor if empty + + * Smarty.class.php + docs/designers.sgml + docs/getting-started.sgml + docs/programmers.sgml: + make use_sub_dirs go back to crc32 for subdir separation + +2002-06-29 Monte Ohrt + + * plugins/function.eval.php: do nothing if $val is empty + + * TODO + plugins/function.eval.php + plugins/function.popup_init.php: + add zindex to popup init, fix error message for eval. + +2002-06-27 Monte Ohrt + + * Smarty.class.php: + only loop through relative paths for PHP include_path, remove $_relative variable + + * Smarty_Compiler.class.php: added {$smarty.version} variable + +2002-06-26 Monte Ohrt + + * docs/appendixes.sgml + docs/designers.sgml + docs/getting-started.sgml + docs/programmers.sgml + Smarty.class.php: + update plugin loading logic, look in SMARTY_DIR, then cwd. If all fail, then retry all with include_path + + * templates/header.tpl + Smarty.class.php: update get_include_path, get _path_array only once + + * Smarty.class.php: fix get_include_path function for windows + + * Smarty.class.php: update plugin search logic + + * Smarty.class.php: only search include_path if relative path + + * plugins/function.html_select_date.php + plugins/function.html_select_time.php + plugins/modifier.date_format.php + Smarty_Compiler.class.php + NEWS + Smarty.class.php: allow plugins_dir to be an array of directories + +2002-06-25 Monte Ohrt + + * docs/programmers.sgml + docs/getting-started.sgml: update installation docs + + * debug.tpl + docs/getting-started.sgml + templates/debug.tpl + NEWS + Smarty.class.php: move debug.tpl to SMARTY_DIR, add to constructor + +2002-06-24 Monte Ohrt + + * plugins/function.assign_debug_info.php + NEWS: fixed warning message in function.assign_debug_info + + * Smarty.class.php: update include_path fixes + + * NEWS: + fixed $template_dir, $compile_dir, $cache_dir, $config_dir to respect include_path + +2002-06-23 Monte Ohrt + + * plugins/shared.make_timestamp.php: + update timestamp plugin to work when passed a timestamp + +2002-06-19 Monte Ohrt + + * NEWS: update NEWS file + + * plugins/modifier.date_format.php + docs/designers.sgml: + update date_format, allow optional 2nd paramater as default date if passed date is empty. update docs. + + * plugins/modifier.date_format.php: + fix date_format modifier, return nothing if given empty string + +2002-06-18 Monte Ohrt + + * NEWS + plugins/function.cycle.php: + gave $reset a default value in cycle function + + * plugins/function.html_select_date.php + plugins/shared.make_timestamp.php + NEWS: + corrected warnings in html_select_time function, made make timestamp always return a timestamp + +2002-06-17 Monte Ohrt + + * Smarty.class.php: swapped around cache_id and compile_id order + +2002-06-14 Monte Ohrt + + * docs/programmers.sgml + plugins/function.popup_init.php + Smarty.class.php: + change directory delimiter to "^" for cache and compile files + +2002-06-13 Andrei Zmievski + + * TODO: done. + + * Smarty_Compiler.class.php: + Optimize the calculation of section 'total' property. + +2002-06-11 Monte Ohrt + + * NEWS + Smarty.class.php: + added support for subdir exclusion, deletion by full or partial cache_id and compile_id, change file format to urlencoded values instead of crc32 + +2002-06-07 Monte Ohrt + + * Smarty.class.php: fix bug with last_modified_check code + + * NEWS + Smarty.class.php: + updated $GLOBALS refererence for HTTP_IF_MODIFIED_SINCE + +2002-06-06 Monte Ohrt + + * docs/designers.sgml + overlib.js: + remove overlib.js file from distribution, update plugin and docs + +2002-06-05 Monte Ohrt + + * docs/designers.sgml + NEWS + Smarty.class.php: fix 304 Not Modified, don't send content + +2002-06-03 Monte Ohrt + + * plugins/function.cycle.php: update version number + + * plugins/function.cycle.php + NEWS: + fixed cycle function to respect delimiter setting after initial setting + + * Smarty.class.php + NEWS: + update $GLOBALS references to work properly with track_globals settings + + * plugins/function.math.php: fixed bug with call $assign + + * docs/appendixes.sgml + docs/designers.sgml + plugins/function.html_options.php + plugins/function.html_select_time.php + NEWS + Smarty.class.php + Smarty_Compiler.class.php: + optimized for loops with count() function calls + +2002-06-01 Andrei Zmievski + + * TODO: *** empty log message *** + +2002-05-21 Monte Ohrt + + * NEWS: update NEWS file + + * plugins/function.html_select_date.php + RESOURCES + docs/designers.sgml + Config_File.class.php: + update html_select_date with month_value_format attribute for controlling the format of the month values. + +2002-05-17 Andrei Zmievski + + * NEWS + Smarty_Compiler.class.php: + Made it possible to use simple variables inside [] for indexing. + +2002-05-16 Monte Ohrt + + * docs/designers.sgml + docs/getting-started.sgml + NEWS + Smarty.class.php + Smarty_Compiler.class.php + TESTIMONIALS: add "once" attribute to php_include, update docs + +2002-05-09 Andrei Zmievski + + * NEWS + TODO: *** empty log message *** + +2002-05-07 Monte Ohrt + + * plugins/function.cycle.php: remove \n from cycle function + + * docs/designers.sgml + plugins/function.cycle.php + README + RELEASE_NOTES + Smarty.class.php + Smarty_Compiler.class.php + NEWS: + update cycle function to handle array as input, update files to 2.1.1 + +2002-05-06 Monte Ohrt + + * plugins/function.fetch.php: + update fetch function with more error checking + +2002-05-03 Monte Ohrt + + * docs/designers.sgml + plugins/function.counter.php: + update counter to use name instead of id (id still works though) + + * plugins/function.cycle.php + docs/designers.sgml: rename id to name for cycle function + + * plugins/function.cycle.php: + update cycle function to allow blank values parameter after initialized + + * plugins/function.cycle.php: fix syntax error + +2002-05-02 Monte Ohrt + + * plugins/function.cycle.php: ugh, another typo + + * plugins/function.cycle.php: update comments + + * docs/designers.sgml + plugins/function.cycle.php + NEWS: added function cycle + + * FAQ + Smarty.class.php: fix register_outputfilter function + +2002-05-01 Monte Ohrt + + * docs/designers.sgml + NEWS + Smarty.class.php: fixed bug with resource testing and include_path + +2002-04-30 Monte Ohrt + + * NEWS + README + RELEASE_NOTES + Smarty.class.php + Smarty_Compiler.class.php: update files for 2.1.0 release + +2002-04-30 Andrei Zmievski + + * plugins/function.fetch.php + docs/programmers.sgml + Smarty.class.php: Fix. + +2002-04-29 Andrei Zmievski + + * docs/programmers.sgml + docs/designers.sgml: A whole bunch of docs. + +2002-04-26 Monte Ohrt + + * FAQ + QUICKSTART + docs/programmers.sgml: update FAQ, QUICKSTART, small doc syntax fix + +2002-04-24 Monte Ohrt + + * docs/programmers.sgml + templates/debug.tpl + Smarty.class.php: changed doc structure a bit + +2002-04-16 Andrei Zmievski + + * Smarty.class.php: Add register/unregister API for output filters. + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php + TODO: + Changed the way filters are loaded, which now has to be done explicitly, + either through load_filter() API or by filling in $autoload_filters variable. + Also renamed internal variable to avoid namespace pollution. + +2002-04-15 Andrei Zmievski + + * Smarty.class.php: + Fixed _get_php_resource() to take include_path into account. + +2002-04-15 Monte Ohrt + + * docs/designers.sgml: + update docs, get modifiers and functions into index for easy access + + * docs/programmers.sgml + NEWS + Smarty.class.php: update caching documentation + +2002-04-15 Andrei Zmievski + + * NEWS: *** empty log message *** + + * Smarty.class.php: Only turn down error notices if $debugging is false. + +2002-04-15 Monte Ohrt + + * NEWS: update NEWS file + + * plugins/function.html_select_date.php: + fixed logic so this works right when field_separator = "/" + + * plugins/function.html_select_date.php: + fix regular expression for matching date + +2002-04-13 Monte Ohrt + + * docs/designers.sgml: updated html_select_date docs to reflect changes + + * NEWS + plugins/function.html_select_date.php: + added YYYY-MM-DD support to html_select_date + +2002-04-12 Andrei Zmievski + + * TESTIMONIALS: New entry. + +2002-04-12 Monte Ohrt + + * plugins/modifier.strip_tags.php: back out changes to strip_tags + + * docs/programmers.sgml: update docs regarding cache_lifetime + + * plugins/modifier.strip_tags.php + Smarty.class.php: + update cache_lifetime logic: -1 = never expire, 0 = always expire + +2002-04-11 Andrei Zmievski + + * BUGS + FAQ + INSTALL + NEWS + Smarty.class.php + Smarty_Compiler.class.php + docs/getting-started.sgml: + Fixed directory separtor issue. Requiring PHP 4.0.6 now. + + * NEWS + Smarty_Compiler.class.php: + Added ability to use simple variables for array indices or object properties. + + * TESTIMONIALS: Another one. + + * TESTIMONIALS: Adding one from Mark P. + +2002-04-05 Andrei Zmievski + + * Smarty_Compiler.class.php + NEWS + Smarty.class.php: Make it possible to unregister pre/postfilter plugins. + +2002-04-05 Monte Ohrt + + * INSTALL: Remove addons file from INSTALL instructions + +2002-04-04 Monte Ohrt + + * docs/designers.sgml: update doc error + + * docs/designers.sgml + plugins/modifier.escape.php + NEWS + Smarty.class.php: added htmlall attribute to escape modifier + +2002-04-03 Andrei Zmievski + + * Smarty_Compiler.class.php: Fixed undefined offset warning in {if} tag. + + * Smarty.class.php + NEWS: Added template_exists() API. + + * Smarty.class.php + Smarty_Compiler.class.php + NEWS: + - Added $smarty.template variable. + - Fixed {include_php} tag when dynamic values were used for 'file' attribute. + + * Config_File.class.php: Separator setting fix. + +2002-03-28 Monte Ohrt + + * FAQ + README: add digest address + + * FAQ + README + Smarty.class.php: update mailing list addresses + +2002-03-28 Andrei Zmievski + + * NEWS: *** empty log message *** + + * plugins/function.html_select_date.php + plugins/function.html_select_time.php + plugins/modifier.date_format.php: + Fix for when plugins directory is not the default one. + +2002-03-28 Andrei Zmievski + + * NEWS: *** empty log message *** + + * plugins/function.html_select_date.php + plugins/function.html_select_time.php + plugins/modifier.date_format.php: + Fix for when plugins directory is not the default one. + +2002-03-27 Monte Ohrt + + * FAQ: update FAQ page + +2002-03-26 Andrei Zmievski + + * CREDITS + NEWS + Smarty.class.php + Smarty_Compiler.class.php + TODO: Block functions changes. + + * Config_File.class.php: *** empty log message *** + +2002-03-25 Andrei Zmievski + + * Smarty.class.php + Smarty_Compiler.class.php: Initial implementation of block functions. + +2002-03-22 Monte Ohrt + + * docs/designers.sgml: fix documentation error in capture + +2002-03-22 Andrei Zmievski + + * Smarty.class.php: *** empty log message *** + + * Smarty.class.php: Turn off notices. + +2002-03-21 Andrei Zmievski + + * Smarty_Compiler.class.php: Make _current_file available to prefilters. + + * NEWS + Smarty.class.php: + Made is possible to assign variables in pre/postfilters. + +2002-03-20 Andrei Zmievski + + * plugins/function.html_select_date.php: Fixed +/- functionality. + + * NEWS: *** empty log message *** + +2002-03-20 Monte Ohrt + + * Config_File.class.php + NEWS + README + RELEASE_NOTES + Smarty.class.php + Smarty_Compiler.class.php: update version numbers + + * plugins/function.html_select_date.php + plugins/function.html_select_time.php + plugins/modifier.date_format.php: + move .make_timestamp.php to shared.make_timestamp.php + + * NEWS + Smarty.class.php + docs/designers.sgml + plugins/function.fetch.php + plugins/function.html_select_date.php: + update file generation, replace crc32() '-' with 'N' + +2002-03-20 Andrei Zmievski + + * Smarty_Compiler.class.php: *** empty log message *** + +2002-03-19 Andrei Zmievski + + * NEWS: *** empty log message *** + + * Smarty.class.php + Smarty_Compiler.class.php: + Fix plugin behavior for inserts with script attribute. + + * NEWS: *** empty log message *** + + * Smarty_Compiler.class.php: Fix bug with $smarty.cookies. + + * TESTIMONIALS: *** empty log message *** + +2002-03-15 Monte Ohrt + + * NEWS + docs/designers.sgml: update Changelog + + * plugins/modifier.indent.php + plugins/modifier.wordwrap.php: add wordwrap and indent to repository + +2002-03-14 Monte Ohrt + + * Smarty.class.php: + remove show_info_include and show_info_header functions + +2002-03-13 Monte Ohrt + + * plugins/function.fetch.php: update fetch function + + * plugins/function.fetch.php: update fetch function with new parameters + +2002-03-12 Monte Ohrt + + * docs/designers.sgml: update doc tables + + * docs/designers.sgml: update docs columns + + * docs/getting-started.sgml + docs/appendixes.sgml: update docs + + * TESTIMONIALS + docs/appendixes.sgml: update syntax error in docs, add to testimonials + +2002-03-04 Monte Ohrt + + * FAQ + README: update FAQ, README with digest mode info + +2002-03-02 Monte Ohrt + + * QUICKSTART: update quickstart + + * Smarty.class.php: + change behavior so cache_lifetime = 0 never expires (instead of always regenerate) + +2002-03-01 Monte Ohrt + + * docs/designers.sgml: update doc example + +2002-03-01 Andrei Zmievski + + * CREDITS + RELEASE_NOTES + TODO + NEWS: *** empty log message *** + +2002-03-01 Monte Ohrt + + * docs/appendixes.sgml + docs/designers.sgml + docs/getting-started.sgml + docs/programmers.sgml: update document id tags + + * docs.sgml: remove docs.sgml + + * RESOURCES + Smarty.class.php: update resources + +2002-02-28 Andrei Zmievski + + * TESTIMONIALS + docs/appendixes.sgml + docs/designers.sgml + docs/programmers.sgml: *** empty log message *** + +2002-02-27 Andrei Zmievski + + * plugins/function.eval.php + docs/designers.sgml: *** empty log message *** + +2002-02-27 Monte Ohrt + + * plugins/function.eval.php: added eval function to plugin dir + +2002-02-27 Andrei Zmievski + + * NEWS: *** empty log message *** + +2002-02-27 Monte Ohrt + + * docs/designers.sgml: fix syntax error + + * docs/appendixes.sgml + docs/designers.sgml + docs/getting-started.sgml + docs/programmers.sgml: convert technical notes to docbook format + + * NEWS + docs/designers.sgml: added "eval" plugin docs + +2002-02-26 Andrei Zmievski + + * docs/programmers.sgml + docs/designers.sgml + docs/appendixes.sgml + docs/getting-started.sgml + docs/html-common.dsl + docs/.cvsignore: *** empty log message *** + + * docs/appendixes.sgml + docs/common.dsl + docs/designers.sgml + docs/getting-started.sgml + docs/html-common.dsl + docs/html.dsl + docs/manual.sgml + docs/preface.sgml + docs/programmers.sgml: Split up docs. + +2002-02-25 Andrei Zmievski + + * docs.sgml: *** empty log message *** + +2002-02-22 Monte Ohrt + + * docs.sgml: update docs + +2002-02-22 Andrei Zmievski + + * docs.sgml + AUTHORS + NEWS: *** empty log message *** + +2002-02-21 Monte Ohrt + + * Config_File.class.php + NEWS + Smarty.class.php + Smarty_Compiler.class.php + docs.sgml: update misc changes + +2002-02-21 Andrei Zmievski + + * docs.sgml: *** empty log message *** + +2002-02-20 Monte Ohrt + + * docs.sgml: misc updates + +2002-02-20 Andrei Zmievski + + * docs.sgml: *** empty log message *** + + * Smarty.class.php + plugins/function.assign.php + plugins/function.assign_debug_info.php + plugins/function.counter.php + plugins/function.fetch.php + plugins/function.math.php + plugins/function.popup.php + plugins/function.popup_init.php + plugins/modifier.escape.php: Fixup some naming. + +2002-02-20 Monte Ohrt + + * docs.sgml: update docs + +2002-02-20 Andrei Zmievski + + * docs.sgml: *** empty log message *** + +2002-02-20 Monte Ohrt + + * NEWS + docs.sgml + plugins/modifier.escape.php: + removed global vars from fetch function, added attrs to escape modifier + + * docs.sgml: add plugin chapter outline + +2002-02-19 Monte Ohrt + + * README + RELEASE_NOTES + RESOURCES + Smarty.class.php + docs.sgml + BUGS + FAQ + INSTALL + QUICKSTART: update docs + +2002-02-19 Andrei Zmievski + + * docs.sgml: Updated resources docs. + + * README: *** empty log message *** + + * docs.sgml: Updated description of {$smarty} variable. + + * BUGS + FAQ + INSTALL + QUICKSTART + RELEASE_NOTES + docs.sgml: Remove PEAR notes. + +2002-02-18 Andrei Zmievski + + * Config_File.class.php + NEWS: Removed dependency on PEAR. + +2002-02-18 Monte Ohrt + + * NEWS + docs.sgml + plugins/function.popup_init.php: add src attribute to popup_init + +2002-02-15 Andrei Zmievski + + * Smarty_Compiler.class.php + plugins/modifier.debug_print_var.php + NEWS + Smarty.class.php: Performance enhancements. + +2002-02-06 Andrei Zmievski + + * plugins/function.html_options.php: + Fix html_options output to be XHTML compatible. + +2002-02-05 Andrei Zmievski + + * Smarty.class.php + Smarty_Compiler.class.php: Fix up plugin inclusion. + + * Smarty.class.php + Smarty_Compiler.class.php + TODO + plugins/function.html_select_date.php + plugins/function.html_select_time.php + plugins/modifier.date_format.php: Fix plugin directory access. + +2002-02-04 Andrei Zmievski + + * .cvsignore + Smarty_Compiler.class.php: *** empty log message *** + +2002-01-31 Andrei Zmievski + + * NEWS: *** empty log message *** + + * Smarty.addons.php + Smarty.class.php + Smarty_Compiler.class.php + TODO + plugins/function.assign.php + plugins/function.assign_debug_info.php + plugins/function.counter.php + plugins/function.fetch.php + plugins/function.html_options.php + plugins/function.html_select_date.php + plugins/function.html_select_time.php + plugins/function.math.php + plugins/function.popup.php + plugins/function.popup_init.php + plugins/modifier.capitalize.php + plugins/modifier.count_characters.php + plugins/modifier.count_paragraphs.php + plugins/modifier.count_sentences.php + plugins/modifier.count_words.php + plugins/modifier.date_format.php + plugins/modifier.debug_print_var.php + plugins/modifier.default.php + plugins/modifier.escape.php + plugins/modifier.lower.php + plugins/modifier.regex_replace.php + plugins/modifier.replace.php + plugins/modifier.spacify.php + plugins/modifier.string_format.php + plugins/modifier.strip_tags.php + plugins/modifier.truncate.php + plugins/modifier.upper.php + plugins/shared.make_timestamp.php + templates/index.tpl + AUTHORS + CREDITS + Config_File.class.php + README: Implemented plugin architecture. + + * NEWS: *** empty log message *** + +2002-01-30 Monte Ohrt + + * NEWS + Smarty.addons.php + Smarty.class.php + docs.sgml: added modifiers wordwrap and indent + +2002-01-28 Monte Ohrt + + * Smarty.class.php + docs.sgml: + add support for is-modified-since headers, adjust a doc example + +2002-01-24 Monte Ohrt + + * Smarty.class.php: cleanup formatting + + * NEWS + Smarty.class.php + docs.sgml: update ChangeLog, remove insert_tag_check parameter + +2002-01-24 Andrei Zmievski + + * plugins/standard.plugin.php: *** empty log message *** + +2002-01-24 Monte Ohrt + + * Smarty.class.php: fix syntax error + + * Smarty.class.php: removed unneccesary test from fetch() + +2002-01-23 Monte Ohrt + + * Smarty.addons.php: update overlib fixes + + * NEWS: update changelog + + * FAQ + NEWS + RESOURCES + Smarty.addons.php: updated overlib fixes + +2001-12-31 Andrei Zmievski + + * NEWS + Smarty.class.php: Fixed compile_id problem. + +2001-12-28 Monte Ohrt + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php: + fixed problem with using assigned var with include_php filepath + +2001-12-21 Monte Ohrt + + * RESOURCES: update RESOURCES + +2001-12-20 Monte Ohrt + + * FAQ + README: update FAQ + +2001-12-18 Monte Ohrt + + * Smarty_Compiler.class.php + docs.sgml + Config_File.class.php + NEWS + README + RELEASE_NOTES + Smarty.addons.php + Smarty.class.php: update version numbers + +2001-12-18 Andrei Zmievski + + * NEWS + Smarty.class.php: Fixed clear_cache(). + +2001-12-14 Monte Ohrt + + * NEWS + Smarty.addons.php: + fixed bug in smarty_make_timestamp introduced in PHP 4.1.0 + +2001-12-13 Monte Ohrt + + * NEWS + Smarty.class.php + docs.sgml: update default function args, fix cached insert debug timing + +2001-12-12 Monte Ohrt + + * docs.sgml: fix syntax error in documentation + + * Smarty.class.php: update default template handling functionality + +2001-12-11 Monte Ohrt + + * Smarty.class.php + Smarty_Compiler.class.php: update file fetching logic + +2001-12-11 Andrei Zmievski + + * NEWS + Smarty.class.php: Added 'script' attribute to {insert..}. + +2001-12-10 Monte Ohrt + + * NEWS + Smarty.class.php: added default template function handler + + * Config_File.class.php + NEWS + README + RELEASE_NOTES + Smarty.addons.php + Smarty.class.php + Smarty_Compiler.class.php: update version numbers in files to 1.5.1 + +2001-12-10 Andrei Zmievski + + * NEWS + Smarty.class.php: Removed error message from the _read_file() method. + + * Smarty.class.php: Fix check for compile and cache IDs. + +2001-12-06 Monte Ohrt + + * QUICKSTART: fix spelling error in QUICKSTART + + * docs.sgml: fixed spelling errors in documenation + + * Smarty_Compiler.class.php + docs.sgml + Config_File.class.php + NEWS + README + RELEASE_NOTES + Smarty.addons.php + Smarty.class.php: commit 1.5.0 release + + * RESOURCES + docs.sgml: added RESOURCES file + +2001-12-05 Andrei Zmievski + + * Smarty_Compiler.class.php: Refactor. + +2001-12-05 Monte Ohrt + + * NEWS + Smarty_Compiler.class.php + docs.sgml: added assign to include and php_include + + * Smarty.class.php + Smarty_Compiler.class.php + docs.sgml: *** empty log message *** + +2001-12-04 Andrei Zmievski + + * NEWS + Smarty_Compiler.class.php: Formatting. + +2001-12-04 Monte Ohrt + + * Smarty_Compiler.class.php + NEWS + Smarty.class.php: update ChangeLog + +2001-12-04 Andrei Zmievski + + * NEWS + Smarty.class.php: Formatting. + +2001-12-04 Monte Ohrt + + * Smarty.class.php: removed SMARTY_DIR setting in constructor + + * Smarty.class.php: fix Smarty.class.php indention error + + * Smarty.class.php: update trusted logic + +2001-12-03 Monte Ohrt + + * Smarty.class.php: + fix up is_secure, is_trusted, make _parse_tpl_path function + + * Smarty.class.php: fix problem with testing SMARTY_DIR as empty + + * NEWS + docs.sgml: update documentation, change log + + * Smarty.class.php: + update constructor to check for SMARTY_DIR before assigning + +2001-12-03 Andrei Zmievski + + * NEWS + Smarty.class.php: *** empty log message *** + +2001-12-03 Monte Ohrt + + * FAQ + INSTALL + RELEASE_NOTES: update a few files + + * NEWS + QUICKSTART + Smarty.class.php + docs.sgml: added trusted_dir functionality, cleaned up secure_dir logic + +2001-12-03 Andrei Zmievski + + * NEWS: *** empty log message *** + + * NEWS + Smarty.class.php: - Introduced $compile_id class variable. + - Fixed a situation where if $cache_id and $compile_id were both null + they were passed to auto functions as empty string instead of null. + +2001-11-30 Monte Ohrt + + * NEWS + Smarty.class.php: + change variable names in fetch() fuction to smarty_* to avoid namespace conflicts + + * NEWS + Smarty.class.php: fixed bug in _rm_auto with catenated null values + +2001-11-29 Andrei Zmievski + + * NEWS + Smarty_Compiler.class.php: Added $smarty.section.* syntax. + + * Smarty_Compiler.class.php: Made 'name' attribute optional for {foreach}. + +2001-11-29 Monte Ohrt + + * Smarty.class.php + index.php: remove assign "now" in index.tpl + +2001-11-29 Andrei Zmievski + + * NEWS + Smarty.addons.php + Smarty.class.php: Fix formatting. + +2001-11-28 Monte Ohrt + + * NEWS + Smarty.class.php + docs.sgml: + removed return statements from _read_cache_file (how did they get in there?) + +2001-11-27 Monte Ohrt + + * docs.sgml + NEWS + Smarty.addons.php + Smarty.class.php: + fixed bugs and added assign attribute to several functions + +2001-11-27 Andrei Zmievski + + * NEWS: Some rewording. + + * Smarty_Compiler.class.php: Fix $smarty.capture access. + + * TODO: *** empty log message *** + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php: + Made {config_load ..} merge globals from each config file only once per scope. + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php: - Added {foreach ...}. + - Made certain $smarty.* references handled at compilation time. + +2001-11-26 Monte Ohrt + + * Config_File.class.php + NEWS + Smarty.class.php + Smarty_Compiler.class.php + docs.sgml: commit cache handler functionality + +2001-11-20 Andrei Zmievski + + * NEWS + Smarty.addons.php + Smarty_Compiler.class.php: Various fixes and additions. + + * NEWS + index.php: *** empty log message *** + +2001-11-05 Monte Ohrt + + * Smarty.class.php: changed _read_file parameter from $end to $lines + + * NEWS + Smarty.class.php: fixed is_cache, make cache reading more efficient + +2001-11-02 Monte Ohrt + + * FAQ + NEWS: update FAQ with mailing list Reply-To header FAQ + + * NEWS + Smarty.class.php + index.php: supress fopen errors, return false if cache file won't load + +2001-11-01 Monte Ohrt + + * QUICKSTART + docs.sgml + index.php: update QUICKSTART guide with index key example + + * Config_File.class.php + NEWS + README + RELEASE_NOTES + Smarty.addons.php + Smarty.class.php + Smarty_Compiler.class.php + docs.sgml: commit all updates for 1.4.6 + +2001-11-01 Andrei Zmievski + + * NEWS: *** empty log message *** + +2001-10-30 Monte Ohrt + + * Smarty.addons.php: fix assign function problem with empty value passed + + * NEWS + Smarty.addons.php + Smarty.class.php + Smarty_Compiler.class.php + templates/debug.tpl: + fixed bug in assign function when passing an empty value + +2001-10-26 Monte Ohrt + + * Smarty.addons.php + Smarty.class.php + index.php: fix minor typo in debug code + +2001-10-26 Andrei Zmievski + + * Smarty.class.php: Typo. + +2001-10-26 Monte Ohrt + + * Smarty.addons.php: + update debug console output, handle html encoding correctly + +2001-10-26 Andrei Zmievski + + * Smarty.addons.php + templates/debug.tpl: Debug formatting. + + * Smarty.class.php: Disable rmdir warning. + +2001-10-26 Monte Ohrt + + * Smarty.addons.php + Smarty.class.php + templates/debug.tpl: update debugging to expand array variables + + * Smarty.class.php + docs.sgml: + update docs for fetching only timestamp with custom template source functions + + * Smarty.addons.php: fix debug console error + +2001-10-26 Andrei Zmievski + + * docs.sgml: Typos. + + * Smarty.addons.php: Cleanup whitespace. + + * Smarty_Compiler.class.php: Clean up whitespace. + + * Smarty.class.php: Cleaning up code, formatting mostly. + + * NEWS: *** empty log message *** + +2001-10-25 Monte Ohrt + + * NEWS + docs.sgml: update documentation to current version + + * NEWS + Smarty.addons.php: + updated fetch to give proper warning when fetching unreadable or nonexistant files + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php: + fixed problem with newline at the end of compiled templates + + * NEWS + Smarty.class.php: recompile cache if config file gets modified too. + + * NEWS + Smarty.class.php: + added feature to regenerate cache if compile_check is enabled and an + involved template is modified + +2001-10-23 Monte Ohrt + + * Smarty.class.php: fix indent for insert tags in debug console + + * templates/debug.tpl: update debug.tpl file format + + * NEWS + Smarty.addons.php + Smarty.class.php + templates/debug.tpl: + update execution time debugging, move into include list + +2001-10-10 Monte Ohrt + + * NEWS + Smarty.addons.php + Smarty.class.php + Smarty_Compiler.class.php: + fixed up execution time output in debug console + +2001-10-09 Andrei Zmievski + + * Config_File.class.php + NEWS + Smarty.class.php + TODO: Added support for hidden config vars. + +2001-10-04 Monte Ohrt + + * NEWS + Smarty.addons.php + Smarty.class.php + templates/debug.tpl: added execution times to debug console + +2001-10-02 Andrei Zmievski + + * Smarty_Compiler.class.php: Add space. + +2001-10-01 Andrei Zmievski + + * Smarty.class.php: Fix reference to compile_id. + +2001-09-28 Andrei Zmievski + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php: Added postfilter functions. + +2001-09-26 Andrei Zmievski + + * NEWS + Smarty.class.php + docs.sgml: Rename to clear_compiled_tpl(). + +2001-09-25 Andrei Zmievski + + * NEWS + Smarty_Compiler.class.php: + Fixed line number reporting when removing comments. + +2001-09-20 Monte Ohrt + + * NEWS + RELEASE_NOTES + Smarty.addons.php: made html_options output xhtml compatible + +2001-09-19 Monte Ohrt + + * Config_File.class.php + NEWS + README + RELEASE_NOTES + Smarty.addons.php + Smarty.class.php + Smarty_Compiler.class.php + templates/debug.tpl: updated version numbers + +2001-09-16 Monte Ohrt + + * FAQ + NEWS + docs.sgml: fix doc error with insert function + +2001-09-06 Andrei Zmievski + + * NEWS: *** empty log message *** + +2001-08-31 Monte Ohrt + + * NEWS: update ChangeLog + + * overlib.js + Smarty.addons.php + Smarty.class.php + docs.sgml: + update overlib to 3.50, adjust addon code so that the overlib.js file isn't modified + +2001-08-31 Andrei Zmievski + + * Smarty.class.php: - compile_id changes + + * NEWS + Smarty.addons.php: - compile_id support + - new options for html_select_date + +2001-08-23 Andrei Zmievski + + * TODO: *** empty log message *** + +2001-08-10 Andrei Zmievski + + * NEWS + Smarty.addons.php + Smarty.class.php + Smarty_Compiler.class.php: + Modified to pass Smarty object as second parameter to insert functions. + Also moved _smarty_mod_handler() and _smarty_insert_handler() into the class. + + * NEWS + Smarty_Compiler.class.php: + Passing Smarty as second parameter to prefilter functions. + +2001-08-09 Andrei Zmievski + + * NEWS: *** empty log message *** + +2001-08-09 Monte Ohrt + + * templates/index.tpl + Smarty.class.php: add smarty.now variable to template + +2001-08-06 Monte Ohrt + + * templates/index.tpl: change config_load section back to setup + +2001-08-06 Andrei Zmievski + + * Smarty.addons.php: Optimize a bit. + +2001-08-04 Monte Ohrt + + * docs.sgml: update capture documentation + +2001-08-03 Monte Ohrt + + * FAQ + NEWS + Smarty.class.php: + fix bug with URL controlled debugging, works now (Monte) + +2001-08-01 Andrei Zmievski + + * Config_File.class.php: *** empty log message *** + + * Smarty_Compiler.class.php + Smarty.class.php: - Fixed some E_NOTICE stuff in compiler. + - Generalized assign_smarty_interface() a bit. + +2001-07-24 Andrei Zmievski + + * NEWS + Smarty_Compiler.class.php + TODO: See ChangeLog for details. + +2001-07-20 Andrei Zmievski + + * Config_File.class.php: Booleanize case-insensitively. + +2001-07-17 Monte Ohrt + + * NEWS: update ChangeLog + + * Smarty.class.php + docs.sgml: put SMARTY_DIR on Config_File require + +2001-07-11 Monte Ohrt + + * docs.sgml + FAQ + NEWS + Smarty.class.php: + updated security to not include insecure docs, only warning + +2001-07-10 Andrei Zmievski + + * Smarty.class.php: Adding 'sizeof' as an allowed {if} function. + +2001-07-06 Andrei Zmievski + + * NEWS: *** empty log message *** + +2001-07-06 Monte Ohrt + + * Config_File.class.php + NEWS + README + RELEASE_NOTES + Smarty.addons.php + Smarty.class.php + Smarty_Compiler.class.php: update version number to 1.4.4 + + * NEWS + Smarty.addons.php + Smarty_Compiler.class.php + docs.sgml + templates/header.tpl + templates/index.tpl: update documenatation, template examples + +2001-07-03 Andrei Zmievski + + * NEWS + Smarty.class.php: Implemented access to request vars via $smarty var. + + * NEWS + Smarty_Compiler.class.php: + Fixed a bug with parsing function arguments in {if} tags. + +2001-06-30 Monte Ohrt + + * NEWS: update ChangeLog + +2001-06-29 Monte Ohrt + + * Smarty.addons.php + Smarty.class.php + docs.sgml + overlib.js: + moved overlib to separate file, added SMARTY_DIR, documented. added much documentation + +2001-06-29 Andrei Zmievski + + * NEWS + RELEASE_NOTES + TODO: *** empty log message *** + +2001-06-29 Monte Ohrt + + * NEWS + README + RELEASE_NOTES + Smarty.addons.php + Smarty.class.php + docs.sgml + index.php + templates/debug.tpl + templates/header.tpl + templates/index.tpl: update release notes + +2001-06-27 Andrei Zmievski + + * Smarty_Compiler.class.php: *** empty log message *** + + * NEWS + Smarty_Compiler.class.php: Implemented 'step' section attribute. + + * Smarty_Compiler.class.php: Negative values of 'max' will mean no max. + + * AUTHORS + NEWS: *** empty log message *** + +2001-06-26 Andrei Zmievski + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php + index.php: Added 'max' and 'start' section attributes. + Added 'total' and 'iteration' section properties. + +2001-06-25 Andrei Zmievski + + * Config_File.class.php + RELEASE_NOTES + Smarty.addons.php + Smarty.class.php + Smarty_Compiler.class.php: Update version numbers. + +2001-06-23 Andrei Zmievski + + * TODO: *** empty log message *** + +2001-06-21 Andrei Zmievski + + * Config_File.class.php + NEWS: Fixed booleanization bug. + +2001-06-20 Monte Ohrt + + * docs.sgml: + update documents to reflect changes to cached content & debugging + +2001-06-20 Andrei Zmievski + + * Smarty.addons.php + Smarty.class.php: Remove debug output for cached and fetched cases. + +2001-06-20 Monte Ohrt + + * Smarty.class.php: update include_info to false + + * Smarty.class.php + docs.sgml + index.php + templates/footer.tpl: + moved debug logic into Smarty completely, created flags for it + +2001-06-19 Andrei Zmievski + + * Smarty.addons.php + Smarty.class.php + templates/debug.tpl: *** empty log message *** + + * NEWS + Smarty.class.php: Remove unneeded debug functions. + +2001-06-19 Monte Ohrt + + * NEWS + Smarty.addons.php + Smarty.class.php + docs.sgml + templates/debug.tpl + templates/footer.tpl: commit updates, add debug template + +2001-06-19 Andrei Zmievski + + * Smarty.class.php + Smarty_Compiler.class.php + TODO: + Moved config loading code inside main class, the compiled template now + simply calls that method. + +2001-06-15 Andrei Zmievski + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php + templates/index.tpl: * moved config array into class itself + * added 'scope' attribute for config_load + + * Smarty_Compiler.class.php + Smarty.addons.php + Smarty.class.php: Finishing up secure mode. + +2001-06-15 Monte Ohrt + + * NEWS: update ChangeLog + + * Smarty_Compiler.class.php: cleaned up logic of if statement security + + * Smarty_Compiler.class.php: update if logic to cover more situations + + * Smarty_Compiler.class.php + docs.sgml: update if statement security feature + +2001-06-14 Andrei Zmievski + + * Smarty.addons.php + Smarty.class.php: *** empty log message *** + + * NEWS + Smarty_Compiler.class.php: + Fixed a bug with quoted strings inside if statements. + +2001-06-13 Monte Ohrt + + * Smarty.addons.php + Smarty.class.php: added secure_dir array for multiple secure directories + + * Smarty.addons.php: update fetch funtion to respect security setting + + * NEWS + Smarty.addons.php + Smarty.class.php + docs.sgml: update documentation, changelog + + * Smarty.addons.php + Smarty.class.php: moved _extract setting to assign functions + + * Smarty.addons.php + Smarty.class.php + Smarty_Compiler.class.php: + added assign/unassign custom functions, ability to re-extract tpl_vars + + * Smarty.class.php + Smarty_Compiler.class.php + docs.sgml + index.php: commit security features + +2001-06-11 Andrei Zmievski + + * Smarty.class.php: Version variable typo. + +2001-06-05 Andrei Zmievski + + * Smarty.class.php: + Create config object in fetch() or just set the config path if it already + exists. + +2001-06-04 Andrei Zmievski + + * Smarty.class.php: *** empty log message *** + + * NEWS + Smarty_Compiler.class.php: + Fixed a problem with $ inside strip tags. + +2001-05-31 Andrei Zmievski + + * NEWS: *** empty log message *** + + * Config_File.class.php: Allow empty config_path. + +2001-05-29 Monte Ohrt + + * Smarty_Compiler.class.php + docs.sgml + NEWS + README + RELEASE_NOTES + Smarty.addons.php + Smarty.class.php: update version numbers + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php + docs.sgml: moved version variable to internal variable + +2001-05-22 Andrei Zmievski + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php: + Moved $_smarty_sections and $_smarty_conf_obj into Smarty class. + +2001-05-18 Monte Ohrt + + * NEWS: update ChangeLog + + * FAQ + QUICKSTART: update FAQ, QUICKSTART for windows include_path setup + + * configs/test.conf: added configs directory to cvs + +2001-05-18 Andrei Zmievski + + * Smarty.class.php: Use compiler_class for including the file. + +2001-05-18 Monte Ohrt + + * docs.sgml: fix typo + +2001-05-16 Monte Ohrt + + * README + RELEASE_NOTES + Smarty.addons.php + Smarty.class.php + Smarty_Compiler.class.php: update files to version 1.4.1 + + * NEWS: update ChangeLog + +2001-05-15 Andrei Zmievski + + * NEWS: *** empty log message *** + + * index.php: forget that! + + * NEWS + Smarty_Compiler.class.php + index.php: Fixed a few E_NOTICE warnings. + +2001-05-09 Monte Ohrt + + * NEWS + RELEASE_NOTES + Smarty.addons.php + Smarty.class.php + docs.sgml: update dates versions + +2001-05-09 Andrei Zmievski + + * NEWS: *** empty log message *** + + * Smarty.class.php: + Use absolute paths when requiring/including Smart components. + + * NEWS: *** empty log message *** + + * Smarty.class.php: Use write mode instead of append. + +2001-05-02 Andrei Zmievski + + * NEWS + Smarty_Compiler.class.php: Fix indexing by section properties. + +2001-05-02 Monte Ohrt + + * NEWS: update changelog + + * Smarty.class.php: remove period from syntax error + +2001-05-02 Andrei Zmievski + + * Smarty_Compiler.class.php: Double-quote the attribute values by default. + +2001-04-30 Monte Ohrt + + * Smarty_Compiler.class.php + NEWS: added simple {capture} logic + +2001-04-30 Andrei Zmievski + + * TODO: *** empty log message *** + + * Smarty_Compiler.class.php + Smarty.class.php: Fix passing config vars to included files. + + * Smarty.class.php + Smarty_Compiler.class.php: Fix inclusion again. + +2001-04-30 Monte Ohrt + + * FAQ + RELEASE_NOTES + Smarty.class.php + misc/fix_vars.php + NEWS: update paths for windows (c:) + +2001-04-28 Andrei Zmievski + + * Smarty.class.php + Smarty_Compiler.class.php: Fix passing variables to included files. + + * templates/index.tpl: *** empty log message *** + +2001-04-27 Andrei Zmievski + + * Smarty_Compiler.class.php: Fix includes. + +2001-04-26 Andrei Zmievski + + * Smarty_Compiler.class.php + docs.sgml + Smarty.class.php: Formatting mostly. + + * Smarty_Compiler.class.php + Config_File.class.php: *** empty log message *** + +2001-04-26 Monte Ohrt + + * Smarty_Compiler.class.php + docs.sgml + FAQ + NEWS + QUICKSTART + RELEASE_NOTES + Smarty.class.php: update docs with new changes + +2001-04-26 Andrei Zmievski + + * RELEASE_NOTES: *** empty log message *** + + * docs.sgml + templates/index.tpl + NEWS + Smarty_Compiler.class.php: Added ability to reference object properties. + +2001-04-25 Andrei Zmievski + + * README + Smarty.addons.php + Smarty.class.php + Smarty_Compiler.class.php + docs.sgml + AUTHORS + Config_File.class.php + CREDITS + RELEASE_NOTES + NEWS: *** empty log message *** + + * docs.sgml: Docs on new parameter to custom functions. + + * NEWS: *** empty log message *** + + * Smarty_Compiler.class.php: + Changing the way tpl vars are referenced and passing smarty object + to custom functions. + + * RELEASE_NOTES + docs.sgml: Fixing docs a bit. + +2001-04-24 Andrei Zmievski + + * docs.sgml: Docs for $compiler_class and compiler functions. + + * templates/index.tpl: *** empty log message *** + + * Smarty_Compiler.class.php: Remove debugging. + +2001-04-24 Monte Ohrt + + * docs.sgml: update compiler function docs + +2001-04-24 Andrei Zmievski + + * NEWS + Smarty.class.php + Smarty_Compiler.class.php + templates/index.tpl: Added compiler function support. + +2001-04-24 Monte Ohrt + + * RELEASE_NOTES + Smarty.class.php: + update notes, change show_info_header to false by default + + * Smarty.class.php + Smarty_Compiler.class.php + docs.sgml + CREDITS + FAQ + NEWS + README + RELEASE_NOTES: update documenation, bug fixes + +2001-04-24 Andrei Zmievski + + * misc/fix_vars.php: Hopefully fix for sure. + +2001-04-23 Monte Ohrt + + * misc/fix_vars.php: uncomment copy/unlink + +2001-04-23 Andrei Zmievski + + * misc/fix_vars.php: Do it more thoroughly. + + * misc/fix_vars.php: check for } + +2001-04-22 Andrei Zmievski + + * misc/fix_vars.php: Fix variable parsing. + +2001-04-20 Monte Ohrt + + * misc/fix_vars.php: fix problem with 4.0.5-dev and preg_replace_callback + +2001-04-19 Monte Ohrt + + * Smarty_Compiler.class.php + docs.sgml + misc/fix_vars.php + NEWS + RELEASE_NOTES + Smarty.class.php: update notes/documentation + + * NEWS + README + RELEASE_NOTES + Smarty.addons.php + Smarty.class.php + Smarty_Compiler.class.php + docs.sgml: update files for 1.4.0 release + +2001-04-16 Andrei Zmievski + + * misc/fix_vars.php: Added fix_vars.php script. + +2001-04-16 Monte Ohrt + + * QUICKSTART + RELEASE_NOTES + docs.sgml + templates/index.tpl: + update RELEASE_NOTES & scripts with new section var syntax + +2001-04-13 Andrei Zmievski + + * Smarty_Compiler.class.php: * Implement new variable format parser. + * Optimizing config load a bit. + +2001-04-13 Monte Ohrt + + * FAQ + NEWS + RELEASE_NOTES + Smarty.class.php: + added $check_cached_insert_tags to speed up cached pages if + {insert ...} is not used (Monte) + +2001-04-12 Andrei Zmievski + + * NEWS + Smarty.class.php + RELEASE_NOTES: *** empty log message *** + + * Smarty_Compiler.class.php: Remove redundant functions. + + * Smarty.class.php: Formatting. + +2001-04-12 Monte Ohrt + + * Smarty.class.php: update file: parsing + + * Smarty.class.php + docs.sgml: update documentation + +2001-04-12 Andrei Zmievski + + * Smarty.class.php + Smarty_Compiler.class.php + TODO: *** empty log message *** + +2001-04-11 Monte Ohrt + + * FAQ + QUICKSTART + RELEASE_NOTES: added RELEASE_NOTES file to cvs + + * NEWS + docs.sgml: update ChangeLog, update documentation + + * Smarty.class.php + Smarty_Compiler.class.php + templates/index.tpl: + update Smarty to compile at run-time. added ability to get files from + absolute paths, added work around for LOCK_EX and windows, changed a few + file permissions to be more secure. + +2001-03-29 Monte Ohrt + + * NEWS + Smarty.addons.php: + allow arbitrary date strings instead of just timestamps + +2001-03-28 Monte Ohrt + + * Smarty.class.php + Smarty_Compiler.class.php + docs.sgml + FAQ + NEWS + README + Smarty.addons.php: + update version in class, update docs for count_ and new vars + + * templates/index.tpl + docs.sgml: update docs, example template + +2001-03-28 Andrei Zmievski + + * Smarty_Compiler.class.php: Some variable renaming. + +2001-03-23 Andrei Zmievski + + * Smarty_Compiler.class.php + NEWS: Fixed nested include infinite repeat bug. + +2001-03-23 Monte Ohrt + + * Smarty.class.php: fix version number + + * Smarty.class.php + NEWS: added optional HTML header to output + +2001-03-22 Andrei Zmievski + + * Smarty_Compiler.class.php: Fixed inclusion of dynamic files. + +2001-03-16 Andrei Zmievski + + * Smarty_Compiler.class.php: Fixing the config_load scoping. + + * Smarty_Compiler.class.php: making config variables global for now. + +2001-03-15 Andrei Zmievski + + * NEWS: *** empty log message *** + + * Smarty_Compiler.class.php: + * Includes are now always done via generated function call to protect + namespace. + * config_load now always uses global config object to improve + performance. + +2001-03-13 Monte Ohrt + + * docs.sgml: update math documentation with format attribute + +2001-03-11 Monte Ohrt + + * docs.sgml + NEWS + Smarty.addons.php + Smarty.class.php + Smarty_Compiler.class.php: update math function with format attribute + +2001-03-10 Andrei Zmievski + + * Smarty.addons.php: *** empty log message *** + + * NEWS + Smarty.addons.php + Smarty.class.php: Added html_select_time custom function. + +2001-03-08 Monte Ohrt + + * Smarty.class.php + Smarty_Compiler.class.php + NEWS + README + Smarty.addons.php: rename 1.3.1b to 1.3.1pl1 + + * NEWS + Smarty.addons.php + Smarty.class.php + Smarty_Compiler.class.php: update version numbers, changelog + + * Smarty.class.php + Smarty_Compiler.class.php: + moved _syntax_error to Smarty_Compiler.class.php + + * Smarty.class.php + docs.sgml: + missing _syntax_error function recovered. fixed minor syntax in docs + +2001-03-07 Monte Ohrt + + * QUICKSTART + README + Smarty.addons.php + Smarty.class.php + Smarty_Compiler.class.php + BUGS + INSTALL + NEWS: update everything to 1.3.1 + +2001-03-03 Monte Ohrt + + * Smarty_Compiler.class.php + Smarty.class.php: fixed bug with cached insert tags + +2001-03-02 Monte Ohrt + + * Smarty.class.php + Smarty_Compiler.class.php: + fix cache fuctions with separated compiled class + + * FAQ + NEWS + docs.sgml: update changelog + +2001-03-02 Andrei Zmievski + + * NEWS + Smarty_Compiler.class.php: Added 'first' and 'last' section properties. + +2001-03-02 Monte Ohrt + + * TODO: remove compiling separation TODO + + * Smarty_Compiler.class.php + Smarty.addons.php + Smarty.class.php: update function headers + + * templates/index.tpl + NEWS + Smarty.class.php + Smarty_Compiler.class.php + index.php: split out compiling code for faster execution + + * Smarty.class.php: fixed a few warning messages + + * Smarty.addons.php + Smarty.class.php + docs.sgml + NEWS: added fetch, unregister mod/fun, updated docs + +2001-03-01 Monte Ohrt + + * Smarty.addons.php: added "int" to available list + + * docs.sgml + FAQ + Smarty.class.php: update FAQ, add math functions & update documetation + + * index.php + Smarty.addons.php + Smarty.class.php + docs.sgml: fixed literal tags and other optional delimiters + +2001-02-26 Andrei Zmievski + + * NEWS + Smarty.class.php: + Added index_prev, index_next section properties and ability to + index by them. + + * NEWS + Smarty.addons.php + Smarty.class.php: Reverting the plugins patch - needs more thought. + + * Smarty.class.php: Fixing plugin loading. + +2001-02-23 Andrei Zmievski + + * Smarty.addons.php + Smarty.class.php + plugins/standard.plugin.php + NEWS: Added plugin functionality. + +2001-02-22 Monte Ohrt + + * docs.sgml + templates/index.tpl + NEWS + README + Smarty.class.php: fixed issue with php tags executed in literal blocks + +2001-02-21 Monte Ohrt + + * NEWS: update changelog for LGPL change + + * Smarty.class.php + docs.sgml + README + Smarty.addons.php: updated version numbers to 1.3.0 + + * NEWS + templates/index.tpl: update changelog, rearrange index.tpl file + +2001-02-21 Andrei Zmievski + + * NEWS + Smarty.class.php: *** empty log message *** + +2001-02-21 Monte Ohrt + + * docs.sgml: update parameters for is_cached and fetch + +2001-02-21 Andrei Zmievski + + * NEWS + Smarty.class.php: *** empty log message *** + +2001-02-21 Monte Ohrt + + * NEWS + Smarty.addons.php + docs.sgml: update docs, remove header function from addons + +2001-02-20 Monte Ohrt + + * FAQ + NEWS: update changelog + + * TODO: update todo + + * TODO: update todo list + + * Smarty.class.php: update php tag handling logic + +2001-02-19 Monte Ohrt + + * index.php + Config_File.class.php + FAQ + Smarty.class.php + docs.sgml: fixed + + * Smarty.addons.php: *** empty log message *** + +2001-02-13 Andrei Zmievski + + * TODO: *** empty log message *** + +2001-02-12 Andrei Zmievski + + * templates/index.tpl + Smarty.class.php: *** empty log message *** + +2001-02-10 Monte Ohrt + + * Smarty.class.php: remove unneeded preg_match + + * Smarty.class.php: remove comment + + * Smarty.class.php: updated php escape to handle +{/if} diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/block.strip.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/block.strip.php new file mode 100644 index 00000000..a25df360 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/block.strip.php @@ -0,0 +1,35 @@ + + * Name: strip
                                                    + * Purpose: strip unwanted white space from text
                                                    + * @link http://smarty.php.net/manual/en/language.function.strip.php {strip} + * (Smarty online manual) + * @param array unused, no parameters for this block + * @param string content of {strip}{/strip} tags + * @param Smarty clever method emulation + * @return string $content stripped of whitespace + */ +function smarty_block_strip($params, $content, &$this) +{ + /* Reformat data between 'strip' and '/strip' tags, removing spaces, tabs and newlines. */ + $_strip_search = array( + "![\t ]+$|^[\t ]+!m", // remove leading/trailing space chars + '%[\r\n]+%m'); // remove CRs and newlines + $_strip_replace = array( + '', + ''); + return preg_replace($_strip_search, $_strip_replace, $content); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/block.textformat.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/block.textformat.php new file mode 100644 index 00000000..f3462c21 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/block.textformat.php @@ -0,0 +1,83 @@ + + * Name: textformat
                                                    + * Purpose: format text a certain way with preset styles + * or custom wrap/indent settings
                                                    + * @link http://smarty.php.net/manual/en/language.function.textformat.php {textformat} + * (Smarty online manual) + * @param array + *
                                                    + * Params:   style: string (email)
                                                    + *           indent: integer (0)
                                                    + *           wrap: integer (80)
                                                    + *           wrap_char string ("\n")
                                                    + *           indent_char: string (" ")
                                                    + *           wrap_boundary: boolean (true)
                                                    + * 
                                                    + * @param string contents of the block + * @param Smarty clever simulation of a method + * @return string string $content re-formatted + */ +function smarty_block_textformat($params, $content, &$smarty) +{ + $style = null; + $indent = 0; + $indent_first = 0; + $indent_char = ' '; + $wrap = 80; + $wrap_char = "\n"; + $wrap_cut = false; + $assign = null; + + if($content == null) { + return true; + } + + extract($params); + + if($style == 'email') { + $wrap = 72; + } + + // split into paragraphs + $paragraphs = preg_split('![\r\n][\r\n]!',$content); + $output = ''; + + foreach($paragraphs as $paragraph) { + if($paragraph == '') { + continue; + } + // convert mult. spaces & special chars to single space + $paragraph = preg_replace(array('!\s+!','!(^\s+)|(\s+$)!'),array(' ',''),$paragraph); + // indent first line + if($indent_first > 0) { + $paragraph = str_repeat($indent_char,$indent_first) . $paragraph; + } + // wordwrap sentences + $paragraph = wordwrap($paragraph, $wrap - $indent, $wrap_char, $wrap_cut); + // indent lines + if($indent > 0) { + $paragraph = preg_replace('!^!m',str_repeat($indent_char,$indent),$paragraph); + } + $output .= $paragraph . $wrap_char . $wrap_char; + } + + if($assign != null) { + $smarty->assign($assign,$output); + } else { + return $output; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.assign.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.assign.php new file mode 100644 index 00000000..c04be8bc --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.assign.php @@ -0,0 +1,38 @@ + + * Name: assign
                                                    + * Purpose: assign a value to a template variable + * @link http://smarty.php.net/manual/en/language.custom.functions.php#LANGUAGE.FUNCTION.ASSIGN {assign} + * (Smarty online manual) + * @param array Format: array('var' => variable name, 'value' => value to assign) + * @param Smarty + */ +function smarty_function_assign($params, &$smarty) +{ + extract($params); + + if (empty($var)) { + $smarty->trigger_error("assign: missing 'var' parameter"); + return; + } + + if (!in_array('value', array_keys($params))) { + $smarty->trigger_error("assign: missing 'value' parameter"); + return; + } + + $smarty->assign($var, $value); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.assign_debug_info.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.assign_debug_info.php new file mode 100644 index 00000000..59ddaa16 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.assign_debug_info.php @@ -0,0 +1,39 @@ + + * Name: assign_debug_info
                                                    + * Purpose: assign debug info to the template
                                                    + * @param array unused in this plugin, this plugin uses {@link Smarty::$_config}, + * {@link Smarty::$_tpl_vars} and {@link Smarty::$_smarty_debug_info} + * @param Smarty + */ +function smarty_function_assign_debug_info($params, &$smarty) +{ + $assigned_vars = $smarty->_tpl_vars; + ksort($assigned_vars); + if (@is_array($smarty->_config[0])) { + $config_vars = $smarty->_config[0]; + ksort($config_vars); + $smarty->assign("_debug_config_keys", array_keys($config_vars)); + $smarty->assign("_debug_config_vals", array_values($config_vars)); + } + + $included_templates = $smarty->_smarty_debug_info; + + $smarty->assign("_debug_keys", array_keys($assigned_vars)); + $smarty->assign("_debug_vals", array_values($assigned_vars)); + + $smarty->assign("_debug_tpls", $included_templates); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.config_load.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.config_load.php new file mode 100644 index 00000000..d9d65b95 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.config_load.php @@ -0,0 +1,130 @@ + + * Name: config_load
                                                    + * Purpose: load config file vars + * @link http://smarty.php.net/manual/en/language.function.config.load.php {config_load} + * (Smarty online manual) + * @param array Format: + *
                                                    + * array('file' => required config file name,
                                                    + *       'section' => optional config file section to load
                                                    + *       'scope' => local/parent/global
                                                    + *       'global' => overrides scope, setting to parent if true)
                                                    + * 
                                                    + * @param Smarty + */ +function smarty_function_config_load($params, &$smarty) +{ + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_microtime.php'); + $_debug_start_time = smarty_core_get_microtime($_params, $smarty); + } + + $_file = isset($params['file']) ? $smarty->_dequote($params['file']) : null; + $_section = isset($params['section']) ? $smarty->_dequote($params['section']) : null; + $_scope = isset($params['scope']) ? $smarty->_dequote($params['scope']) : 'global'; + $_global = isset($params['global']) ? $smarty->_dequote($params['global']) : false; + + if (!isset($_file) || strlen($_file) == 0) { + $smarty->_syntax_error("missing 'file' attribute in config_load tag", E_USER_ERROR, __FILE__, __LINE__); + } + + if (isset($_scope)) { + if ($_scope != 'local' && + $_scope != 'parent' && + $_scope != 'global') { + $smarty->_syntax_error("invalid 'scope' attribute value", E_USER_ERROR, __FILE__, __LINE__); + } + } else { + if ($_global) { + $_scope = 'parent'; + } else { + $_scope = 'local'; + } + } + + if(@is_dir($smarty->config_dir)) { + $_config_dir = $smarty->config_dir; + } else { + // config_dir not found, try include_path + $_params = array('file_path' => $smarty->config_dir); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_include_path.php'); + smarty_core_get_include_path($_params, $smarty); + $_config_dir = $_params['new_file_path']; + } + + $_file_path = $_config_dir . DIRECTORY_SEPARATOR . $_file; + if (isset($_section)) + $_compile_file = $smarty->_get_compile_path($_file_path.'|'.$_section); + else + $_compile_file = $smarty->_get_compile_path($_file_path); + + if($smarty->force_compile + || !file_exists($_compile_file) + || ($smarty->compile_check + && !$smarty->_is_compiled($_file_path, $_compile_file))) { + // compile config file + if(!is_object($smarty->_conf_obj)) { + require_once SMARTY_DIR . $smarty->config_class . '.class.php'; + $smarty->_conf_obj = new $smarty->config_class($_config_dir); + $smarty->_conf_obj->overwrite = $smarty->config_overwrite; + $smarty->_conf_obj->booleanize = $smarty->config_booleanize; + $smarty->_conf_obj->read_hidden = $smarty->config_read_hidden; + $smarty->_conf_obj->fix_newlines = $smarty->config_fix_newlines; + $smarty->_conf_obj->set_path = $_config_dir; + } + $_config_vars = array_merge($smarty->_conf_obj->get($_file), + $smarty->_conf_obj->get($_file, $_section)); + if(function_exists('var_export')) { + $_output = ''; + } else { + $_output = ''\\\'', '\\'=>'\\\\')) . '\'); ?>'; + } + $_params = (array('compile_path' => $_compile_file, 'compiled_content' => $_output, 'resource_timestamp' => filemtime($_file_path))); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.write_compiled_resource.php'); + smarty_core_write_compiled_resource($_params, $smarty); + } else { + include($_compile_file); + } + + if ($smarty->caching) { + $smarty->_cache_info['config'][$_file] = true; + } + + $smarty->_config[0]['vars'] = @array_merge($smarty->_config[0]['vars'], $_config_vars); + $smarty->_config[0]['files'][$_file] = true; + + if ($_scope == 'parent') { + $smarty->_config[1]['vars'] = @array_merge($smarty->_config[1]['vars'], $_config_vars); + $smarty->_config[1]['files'][$_file] = true; + } else if ($_scope == 'global') { + for ($i = 1, $for_max = count($smarty->_config); $i < $for_max; $i++) { + $smarty->_config[$i]['vars'] = @array_merge($smarty->_config[$i]['vars'], $_config_vars); + $smarty->_config[$i]['files'][$_file] = true; + } + } + + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_microtime.php'); + $smarty->_smarty_debug_info[] = array('type' => 'config', + 'filename' => $_file.' ['.$_section.'] '.$_scope, + 'depth' => $smarty->_inclusion_depth, + 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time); + } + +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.counter.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.counter.php new file mode 100644 index 00000000..8d17d2bb --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.counter.php @@ -0,0 +1,88 @@ + + * Name: counter
                                                    + * Purpose: print out a counter value + * @link http://smarty.php.net/manual/en/language.function.counter.php {counter} + * (Smarty online manual) + * @param array parameters + * @param Smarty + * @return string|null + */ +function smarty_function_counter($params, &$smarty) +{ + static $counters = array(); + + extract($params); + + if (!isset($name)) { + if(isset($id)) { + $name = $id; + } else { + $name = "default"; + } + } + + if (!isset($counters[$name])) { + $counters[$name] = array( + 'start'=>1, + 'skip'=>1, + 'direction'=>'up', + 'count'=>1 + ); + } + $counter =& $counters[$name]; + + if (isset($start)) { + $counter['start'] = $counter['count'] = $start; + } + + if (!empty($assign)) { + $counter['assign'] = $assign; + } + + if (isset($counter['assign'])) { + $smarty->assign($counter['assign'], $counter['count']); + } + + if (isset($print)) { + $print = (bool)$print; + } else { + $print = empty($counter['assign']); + } + + if ($print) { + $retval = $counter['count']; + } else { + $retval = null; + } + + if (isset($skip)) { + $counter['skip'] = $skip; + } + + if (isset($direction)) { + $counter['direction'] = $direction; + } + + if ($counter['direction'] == "down") + $counter['count'] -= $counter['skip']; + else + $counter['count'] += $counter['skip']; + + return $retval; + +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.cycle.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.cycle.php new file mode 100644 index 00000000..c2e899d0 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.cycle.php @@ -0,0 +1,119 @@ + + * Name: cycle
                                                    + * Date: May 3, 2002
                                                    + * Purpose: cycle through given values
                                                    + * Input: + * - name = name of cycle (optional) + * - values = comma separated list of values to cycle, + * or an array of values to cycle + * (this can be left out for subsequent calls) + * - reset = boolean - resets given var to true + * - print = boolean - print var or not. default is true + * - advance = boolean - whether or not to advance the cycle + * - delimiter = the value delimiter, default is "," + * - assign = boolean, assigns to template var instead of + * printed. + * + * Examples:
                                                    + *
                                                    + * {cycle values="#eeeeee,#d0d0d0d"}
                                                    + * {cycle name=row values="one,two,three" reset=true}
                                                    + * {cycle name=row}
                                                    + * 
                                                    + * @link http://smarty.php.net/manual/en/language.function.cycle.php {cycle} + * (Smarty online manual) + * @author Monte Ohrt + * @author credit to Mark Priatel + * @author credit to Gerard + * @author credit to Jason Sweat + * @version 1.3 + * @param array + * @param Smarty + * @return string|null + */ +function smarty_function_cycle($params, &$smarty) +{ + static $cycle_vars; + + extract($params); + + if (empty($name)) { + $name = 'default'; + } + + if (!isset($print)) { + $print = true; + } + + if (!isset($advance)) { + $advance = true; + } + + if (!isset($reset)) { + $reset = false; + } + + if (!in_array('values', array_keys($params))) { + if(!isset($cycle_vars[$name]['values'])) { + $smarty->trigger_error("cycle: missing 'values' parameter"); + return; + } + } else { + if(isset($cycle_vars[$name]['values']) + && $cycle_vars[$name]['values'] != $values ) { + $cycle_vars[$name]['index'] = 0; + } + $cycle_vars[$name]['values'] = $values; + } + + if (isset($delimiter)) { + $cycle_vars[$name]['delimiter'] = $delimiter; + } elseif (!isset($cycle_vars[$name]['delimiter'])) { + $cycle_vars[$name]['delimiter'] = ','; + } + + if(!is_array($cycle_vars[$name]['values'])) { + $cycle_array = explode($cycle_vars[$name]['delimiter'],$cycle_vars[$name]['values']); + } else { + $cycle_array = $cycle_vars[$name]['values']; + } + + if(!isset($cycle_vars[$name]['index']) || $reset ) { + $cycle_vars[$name]['index'] = 0; + } + + if (isset($assign)) { + $print = false; + $smarty->assign($assign, $cycle_array[$cycle_vars[$name]['index']]); + } + + if($print) { + $retval = $cycle_array[$cycle_vars[$name]['index']]; + } else { + $retval = null; + } + + if($advance) { + if ( $cycle_vars[$name]['index'] >= count($cycle_array) -1 ) { + $cycle_vars[$name]['index'] = 0; + } else { + $cycle_vars[$name]['index']++; + } + } + + return $retval; +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.debug.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.debug.php new file mode 100644 index 00000000..5fe02f30 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.debug.php @@ -0,0 +1,35 @@ + + * Name: debug
                                                    + * Date: July 1, 2002
                                                    + * Purpose: popup debug window + * @link http://smarty.php.net/manual/en/language.function.debug.php {debug} + * (Smarty online manual) + * @author Monte Ohrt + * @version 1.0 + * @param array + * @param Smarty + * @return string output from {@link Smarty::_generate_debug_output()} + */ +function smarty_function_debug($params, &$smarty) +{ + if($params['output']) { + $smarty->assign('_smarty_debug_output',$params['output']); + } + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.display_debug_console.php'); + return smarty_core_display_debug_console(null, $smarty); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.eval.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.eval.php new file mode 100644 index 00000000..e6943876 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.eval.php @@ -0,0 +1,48 @@ + + * Name: eval
                                                    + * Purpose: evaluate a template variable as a template
                                                    + * @link http://smarty.php.net/manual/en/language.function.eval.php {eval} + * (Smarty online manual) + * @param array + * @param Smarty + */ +function smarty_function_eval($params, &$smarty) +{ + + if (!isset($params['var'])) { + $smarty->trigger_error("eval: missing 'var' parameter"); + return; + } + + if($params['var'] == '') { + return; + } + + $smarty->_compile_source('evaluated template', $params['var'], $_var_compiled); + + ob_start(); + $smarty->_eval('?>' . $_var_compiled); + $_contents = ob_get_contents(); + ob_end_clean(); + + if (!empty($params['assign'])) { + $smarty->assign($params['assign'], $_contents); + } else { + return $_contents; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.fetch.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.fetch.php new file mode 100644 index 00000000..082c3483 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.fetch.php @@ -0,0 +1,217 @@ + + * Name: fetch
                                                    + * Purpose: fetch file, web or ftp data and display results + * @link http://smarty.php.net/manual/en/language.function.fetch.php {fetch} + * (Smarty online manual) + * @param array + * @param Smarty + * @return string|null if the assign parameter is passed, Smarty assigns the + * result to a template variable + */ +function smarty_function_fetch($params, &$smarty) +{ + if (empty($params['file'])) { + $smarty->_trigger_fatal_error("[plugin] parameter 'file' cannot be empty"); + return; + } + + if ($smarty->security && !preg_match('!^(http|ftp)://!i', $params['file'])) { + $_params = array('resource_type' => 'file', 'resource_name' => $params['file']); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.is_secure.php'); + if(!smarty_core_is_secure($_params, $smarty)) { + $smarty->_trigger_fatal_error('[plugin] (secure mode) fetch \'' . $params['file'] . '\' is not allowed'); + return; + } + + // fetch the file + if($fp = @fopen($params['file'],'r')) { + while(!feof($fp)) { + $content .= fgets ($fp,4096); + } + fclose($fp); + } else { + $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] . '\''); + return; + } + } else { + // not a local file + if(preg_match('!^http://!i',$params['file'])) { + // http fetch + if($uri_parts = parse_url($params['file'])) { + // set defaults + $host = $server_name = $uri_parts['host']; + $timeout = 30; + $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"; + $agent = "Smarty Template Engine ".$smarty->_version; + $referer = ""; + $uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/'; + $uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : ''; + $_is_proxy = false; + if(empty($uri_parts['port'])) { + $port = 80; + } else { + $port = $uri_parts['port']; + } + if(empty($uri_parts['user'])) { + $user = ''; + } + // loop through parameters, setup headers + foreach($params as $param_key => $param_value) { + switch($param_key) { + case "file": + case "assign": + case "assign_headers": + break; + case "user": + if(!empty($param_value)) { + $user = $param_value; + } + break; + case "pass": + if(!empty($param_value)) { + $pass = $param_value; + } + break; + case "accept": + if(!empty($param_value)) { + $accept = $param_value; + } + break; + case "header": + if(!empty($param_value)) { + if(!preg_match('![\w\d-]+: .+!',$param_value)) { + $smarty->_trigger_fatal_error("[plugin] invalid header format '".$param_value."'"); + return; + } else { + $extra_headers[] = $param_value; + } + } + break; + case "proxy_host": + if(!empty($param_value)) { + $proxy_host = $param_value; + } + break; + case "proxy_port": + if(!preg_match('!\D!', $param_value)) { + $proxy_port = (int) $param_value; + } else { + $smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'"); + return; + } + break; + case "agent": + if(!empty($param_value)) { + $agent = $param_value; + } + break; + case "referer": + if(!empty($param_value)) { + $referer = $param_value; + } + break; + case "timeout": + if(!preg_match('!\D!', $param_value)) { + $timeout = (int) $param_value; + } else { + $smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'"); + return; + } + break; + default: + $smarty->_trigger_fatal_error("[plugin] unrecognized attribute '".$param_key."'"); + return; + } + } + if(!empty($proxy_host) && !empty($proxy_port)) { + $_is_proxy = true; + $fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout); + } else { + $fp = fsockopen($server_name,$port,$errno,$errstr,$timeout); + } + + if(!$fp) { + $smarty->_trigger_fatal_error("[plugin] unable to fetch: $errstr ($errno)"); + return; + } else { + if($_is_proxy) { + fputs($fp, 'GET ' . $params['file'] . " HTTP/1.0\r\n"); + } else { + fputs($fp, "GET $uri HTTP/1.0\r\n"); + } + if(!empty($host)) { + fputs($fp, "Host: $host\r\n"); + } + if(!empty($accept)) { + fputs($fp, "Accept: $accept\r\n"); + } + if(!empty($agent)) { + fputs($fp, "User-Agent: $agent\r\n"); + } + if(!empty($referer)) { + fputs($fp, "Referer: $referer\r\n"); + } + if(isset($extra_headers) && is_array($extra_headers)) { + foreach($extra_headers as $curr_header) { + fputs($fp, $curr_header."\r\n"); + } + } + if(!empty($user) && !empty($pass)) { + fputs($fp, "Authorization: BASIC ".base64_encode("$user:$pass")."\r\n"); + } + + $content = ''; + fputs($fp, "\r\n"); + while(!feof($fp)) { + $content .= fgets($fp,4096); + } + fclose($fp); + $csplit = split("\r\n\r\n",$content,2); + + $content = $csplit[1]; + + if(!empty($params['assign_headers'])) { + $smarty->assign($params['assign_headers'],split("\r\n",$csplit[0])); + } + } + } else { + $smarty->_trigger_fatal_error("[plugin] unable to parse URL, check syntax"); + return; + } + } else { + // ftp fetch + if($fp = @fopen($params['file'],'r')) { + while(!feof($fp)) { + $content .= fgets ($fp,4096); + } + fclose($fp); + } else { + $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] .'\''); + return; + } + } + + } + + + if (!empty($params['assign'])) { + $smarty->assign($params['assign'],$content); + } else { + return $content; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_checkboxes.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_checkboxes.php new file mode 100644 index 00000000..6b32c594 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_checkboxes.php @@ -0,0 +1,135 @@ + + * Type: function
                                                    + * Name: html_checkboxes
                                                    + * Date: 24.Feb.2003
                                                    + * Purpose: Prints out a list of checkbox input types
                                                    + * Input:
                                                    + * - name (optional) - string default "checkbox" + * - values (required) - array + * - options (optional) - associative array + * - checked (optional) - array default not set + * - separator (optional) - ie
                                                    or   + * - output (optional) - without this one the buttons don't have names + * Examples: + *
                                                    + * {html_checkboxes values=$ids output=$names}
                                                    + * {html_checkboxes values=$ids name='box' separator='
                                                    ' output=$names} + * {html_checkboxes values=$ids checked=$checked separator='
                                                    ' output=$names} + *
                                                    + * @link http://smarty.php.net/manual/en/language.function.html.checkboxes.php {html_checkboxes} + * (Smarty online manual) + * @author Christopher Kvarme + * @author credits to Monte Ohrt + * @version 1.0 + * @param array + * @param Smarty + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_checkboxes($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); + + $name = 'checkbox'; + $values = null; + $options = null; + $selected = null; + $separator = ''; + $labels = true; + $output = null; + + $extra = ''; + + foreach($params as $_key => $_val) { + switch($_key) { + case 'name': + case 'separator': + $$_key = $_val; + break; + + case 'labels': + $$_key = (bool)$_val; + break; + + case 'options': + $$_key = (array)$_val; + break; + + case 'values': + case 'output': + $$_key = array_values((array)$_val); + break; + + case 'checked': + case 'selected': + $selected = array_values((array)$_val); + break; + + case 'checkboxes': + $smarty->trigger_error('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING); + $options = (array)$_val; + break; + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + $smarty->trigger_error("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (!isset($options) && !isset($values)) + return ''; /* raise error here? */ + + settype($selected, 'array'); + $_html_result = ''; + + if (is_array($options)) { + + foreach ($options as $_key=>$_val) + $_html_result .= smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + + + } else { + foreach ($values as $_i=>$_key) { + $_val = isset($output[$_i]) ? $output[$_i] : ''; + $_html_result .= smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + } + + } + + return $_html_result; + +} + +function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels) { + $_output = ''; + if ($labels) $_output .= ''; + $_output .= $separator . "\n"; + + return $_output; +} + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_image.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_image.php new file mode 100644 index 00000000..5ddbe4a1 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_image.php @@ -0,0 +1,143 @@ + + * Name: html_image
                                                    + * Date: Feb 24, 2003
                                                    + * Purpose: format HTML tags for the image
                                                    + * Input:
                                                    + * - file = file (and path) of image (required) + * - border = border width (optional, default 0) + * - height = image height (optional, default actual height) + * - image =image width (optional, default actual width) + * - basedir = base directory for absolute paths, default + * is environment variable DOCUMENT_ROOT + * + * Examples: {html_image file="images/masthead.gif"} + * Output: + * @link http://smarty.php.net/manual/en/language.function.html.image.php {html_image} + * (Smarty online manual) + * @author Monte Ohrt + * @author credits to Duda - wrote first image function + * in repository, helped with lots of functionality + * @version 1.0 + * @param array + * @param Smarty + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_image($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); + + $alt = ''; + $file = ''; + $border = 0; + $height = ''; + $width = ''; + $extra = ''; + $prefix = ''; + $suffix = ''; + $basedir = isset($GLOBALS['HTTP_SERVER_VARS']['DOCUMENT_ROOT']) + ? $GLOBALS['HTTP_SERVER_VARS']['DOCUMENT_ROOT'] : ''; + if(strstr($GLOBALS['HTTP_SERVER_VARS']['HTTP_USER_AGENT'], 'Mac')) { + $dpi_default = 72; + } else { + $dpi_default = 96; + } + + foreach($params as $_key => $_val) { + switch($_key) { + case 'file': + case 'border': + case 'height': + case 'width': + case 'dpi': + case 'basedir': + $$_key = $_val; + break; + + case 'alt': + if(!is_array($_val)) { + $$_key = smarty_function_escape_special_chars($_val); + } else { + $smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + + case 'link': + case 'href': + $prefix = ''; + $suffix = ''; + break; + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + $smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (empty($file)) { + $smarty->trigger_error("html_image: missing 'file' parameter", E_USER_NOTICE); + return; + } + + if (substr($file,0,1) == '/') { + $_image_path = $basedir . $file; + } else { + $_image_path = $file; + } + + if(!isset($params['width']) || !isset($params['height'])) { + if(!$_image_data = @getimagesize($_image_path)) { + if(!file_exists($_image_path)) { + $smarty->trigger_error("html_image: unable to find '$_image_path'", E_USER_NOTICE); + return; + } else if(!is_readable($_image_path)) { + $smarty->trigger_error("html_image: unable to read '$_image_path'", E_USER_NOTICE); + return; + } else { + $smarty->trigger_error("html_image: '$_image_path' is not a valid image file", E_USER_NOTICE); + return; + } + } + $_params = array('resource_type' => 'file', 'resource_name' => $_image_path); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.is_secure.php'); + if(!$smarty->security && !smarty_core_is_secure($_params, $smarty)) { + $smarty->trigger_error("html_image: (secure) '$_image_path' not in secure directory", E_USER_NOTICE); + return; + } + + if(!isset($params['width'])) { + $width = $_image_data[0]; + } + if(!isset($params['height'])) { + $height = $_image_data[1]; + } + + } + + if(isset($params['dpi'])) { + $_resize = $dpi_default/$params['dpi']; + $width = round($width * $_resize); + $height = round($height * $_resize); + } + + return $prefix . ''.$alt.'' . $suffix; +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_options.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_options.php new file mode 100644 index 00000000..dfc38c83 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_options.php @@ -0,0 +1,118 @@ + + * Name: html_options
                                                    + * Input:
                                                    + * - name (optional) - string default "select" + * - values (required if no options supplied) - array + * - options (required if no values supplied) - associative array + * - selected (optional) - string default not set + * - output (required if not options supplied) - array + * Purpose: Prints the list of ' . "\n"; + foreach ($values as $key => $value) { + $optgroup_html .= smarty_function_html_options_optoutput($key, $value, $selected); + } + $optgroup_html .= "\n"; + return $optgroup_html; +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_radios.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_radios.php new file mode 100644 index 00000000..f5052391 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_radios.php @@ -0,0 +1,138 @@ + + * Type: function
                                                    + * Name: html_radios
                                                    + * Date: 24.Feb.2003
                                                    + * Purpose: Prints out a list of radio input types
                                                    + * Input:
                                                    + * - name (optional) - string default "radio" + * - values (required) - array + * - options (optional) - associative array + * - checked (optional) - array default not set + * - separator (optional) - ie
                                                    or   + * - output (optional) - without this one the buttons don't have names + * Examples: + *
                                                    + * {html_radios values=$ids output=$names}
                                                    + * {html_radios values=$ids name='box' separator='
                                                    ' output=$names} + * {html_radios values=$ids checked=$checked separator='
                                                    ' output=$names} + *
                                                    + * @link http://smarty.php.net/manual/en/language.function.html.radios.php {html_radios} + * (Smarty online manual) + * @author Christopher Kvarme + * @author credits to Monte Ohrt + * @version 1.0 + * @param array + * @param Smarty + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_radios($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); + + $name = 'radio'; + $values = null; + $options = null; + $selected = null; + $separator = ''; + $labels = true; + $output = null; + $extra = ''; + + foreach($params as $_key => $_val) { + switch($_key) { + case 'name': + case 'separator': + $$_key = (string)$_val; + break; + + case 'checked': + case 'selected': + if(is_array($_val)) { + $smarty->trigger_error('html_radios: the "' . $_key . '" attribute cannot be an array', E_USER_WARNING); + } else { + $selected = (string)$_val; + } + break; + + case 'labels': + $$_key = (bool)$_val; + break; + + case 'options': + $$_key = (array)$_val; + break; + + case 'values': + case 'output': + $$_key = array_values((array)$_val); + break; + + case 'radios': + $smarty->trigger_error('html_radios: the use of the "radios" attribute is deprecated, use "options" instead', E_USER_WARNING); + $options = (array)$_val; + break; + + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + $smarty->trigger_error("html_radios: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (!isset($options) && !isset($values)) + return ''; /* raise error here? */ + + $_html_result = ''; + + if (isset($options) && is_array($options)) { + + foreach ((array)$options as $_key=>$_val) + $_html_result .= smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + + } else { + + foreach ((array)$values as $_i=>$_key) { + $_val = isset($output[$_i]) ? $output[$_i] : ''; + $_html_result .= smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + } + + } + + return $_html_result; + +} + +function smarty_function_html_radios_output($name, $value, $output, $selected, $extra, $separator, $labels) { + $_output = ''; + if ($labels) $_output .= ''; + $_output .= $separator . "\n"; + + return $_output; +} + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_select_date.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_select_date.php new file mode 100644 index 00000000..a607f555 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_select_date.php @@ -0,0 +1,243 @@ + + * Name: html_select_date
                                                    + * Purpose: Prints the dropdowns for date selection. + * + * ChangeLog:
                                                    + * - 1.0 initial release + * - 1.1 added support for +/- N syntax for begin + * and end year values. (Monte) + * - 1.2 added support for yyyy-mm-dd syntax for + * time value. (Jan Rosier) + * - 1.3 added support for choosing format for + * month values (Gary Loescher) + * - 1.3.1 added support for choosing format for + * day values (Marcus Bointon) + * @link http://smarty.php.net/manual/en/language.function.html.select.date.php {html_select_date} + * (Smarty online manual) + * @version 1.3 + * @author Andrei Zmievski + * @param array + * @param Smarty + * @return string + */ +function smarty_function_html_select_date($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','make_timestamp'); + require_once $smarty->_get_plugin_filepath('function','html_options'); + /* Default values. */ + $prefix = "Date_"; + $start_year = strftime("%Y"); + $end_year = $start_year; + $display_days = true; + $display_months = true; + $display_years = true; + $month_format = "%B"; + /* Write months as numbers by default GL */ + $month_value_format = "%m"; + $day_format = "%02d"; + /* Write day values using this format MB */ + $day_value_format = "%d"; + $year_as_text = false; + /* Display years in reverse order? Ie. 2000,1999,.... */ + $reverse_years = false; + /* Should the select boxes be part of an array when returned from PHP? + e.g. setting it to "birthday", would create "birthday[Day]", + "birthday[Month]" & "birthday[Year]". Can be combined with prefix */ + $field_array = null; + /* tags. + If not set, uses default dropdown. */ + $day_size = null; + $month_size = null; + $year_size = null; + /* Unparsed attributes common to *ALL* the tags. + An example might be in the template: all_extra ='class ="foo"'. */ + $all_extra = null; + /* Separate attributes for the tags. */ + $day_extra = null; + $month_extra = null; + $year_extra = null; + /* Order in which to display the fields. + "D" -> day, "M" -> month, "Y" -> year. */ + $field_order = 'MDY'; + /* String printed between the different fields. */ + $field_separator = "\n"; + $time = time(); + + + extract($params); + + // If $time is not in format yyyy-mm-dd + if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $time)) { + // then $time is empty or unix timestamp or mysql timestamp + // using smarty_make_timestamp to get an unix timestamp and + // strftime to make yyyy-mm-dd + $time = strftime('%Y-%m-%d', smarty_make_timestamp($time)); + } + // Now split this in pieces, which later can be used to set the select + $time = explode("-", $time); + + // make syntax "+N" or "-N" work with start_year and end_year + if (preg_match('!^(\+|\-)\s*(\d+)$!', $end_year, $match)) { + if ($match[1] == '+') { + $end_year = strftime('%Y') + $match[2]; + } else { + $end_year = strftime('%Y') - $match[2]; + } + } + if (preg_match('!^(\+|\-)\s*(\d+)$!', $start_year, $match)) { + if ($match[1] == '+') { + $start_year = strftime('%Y') + $match[2]; + } else { + $start_year = strftime('%Y') - $match[2]; + } + } + + $field_order = strtoupper($field_order); + + $html_result = $month_result = $day_result = $year_result = ""; + + if ($display_months) { + $month_names = array(); + $month_values = array(); + + for ($i = 1; $i <= 12; $i++) { + $month_names[] = strftime($month_format, mktime(0, 0, 0, $i, 1, 2000)); + $month_values[] = strftime($month_value_format, mktime(0, 0, 0, $i, 1, 2000)); + } + + $month_result .= ''; + } + + if ($display_days) { + $days = array(); + for ($i = 1; $i <= 31; $i++) { + $days[] = sprintf($day_format, $i); + $day_values[] = sprintf($day_value_format, $i); + } + + $day_result .= ''; + } + + if ($display_years) { + if (null !== $field_array){ + $year_name = $field_array . '[' . $prefix . 'Year]'; + } else { + $year_name = $prefix . 'Year'; + } + if ($year_as_text) { + $year_result .= ' $years, + 'values' => $years, + 'selected' => $time[0], + 'print_result' => false), + $smarty); + $year_result .= ''; + } + } + + // Loop thru the field_order field + for ($i = 0; $i <= 2; $i++){ + $c = substr($field_order, $i, 1); + switch ($c){ + case 'D': + $html_result .= $day_result; + break; + + case 'M': + $html_result .= $month_result; + break; + + case 'Y': + $html_result .= $year_result; + break; + } + // Add the field seperator + if($i != 2) { + $html_result .= $field_separator; + } + } + + return $html_result; +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_select_time.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_select_time.php new file mode 100644 index 00000000..4643136b --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_select_time.php @@ -0,0 +1,163 @@ + + * Name: html_select_time
                                                    + * Purpose: Prints the dropdowns for time selection + * @link http://smarty.php.net/manual/en/language.function.html.select.time.php {html_select_time} + * (Smarty online manual) + * @param array + * @param Smarty + * @return string + * @uses smarty_make_timestamp() + */ +function smarty_function_html_select_time($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','make_timestamp'); + require_once $smarty->_get_plugin_filepath('function','html_options'); + /* Default values. */ + $prefix = "Time_"; + $time = time(); + $display_hours = true; + $display_minutes = true; + $display_seconds = true; + $display_meridian = true; + $use_24_hours = true; + $minute_interval = 1; + $second_interval = 1; + /* Should the select boxes be part of an array when returned from PHP? + e.g. setting it to "birthday", would create "birthday[Hour]", + "birthday[Minute]", "birthday[Seconds]" & "birthday[Meridian]". + Can be combined with prefix. */ + $field_array = null; + $all_extra = null; + $hour_extra = null; + $minute_extra = null; + $second_extra = null; + $meridian_extra = null; + + extract($params); + + $time = smarty_make_timestamp($time); + + $html_result = ''; + + if ($display_hours) { + $hours = $use_24_hours ? range(0, 23) : range(1, 12); + $hour_fmt = $use_24_hours ? '%H' : '%I'; + for ($i = 0, $for_max = count($hours); $i < $for_max; $i++) + $hours[$i] = sprintf('%02d', $hours[$i]); + $html_result .= '\n"; + } + + if ($display_minutes) { + $all_minutes = range(0, 59); + for ($i = 0, $for_max = count($all_minutes); $i < $for_max; $i+= $minute_interval) + $minutes[] = sprintf('%02d', $all_minutes[$i]); + $selected = intval(floor(strftime('%M', $time) / $minute_interval) * $minute_interval); + $html_result .= '\n"; + } + + if ($display_seconds) { + $all_seconds = range(0, 59); + for ($i = 0, $for_max = count($all_seconds); $i < $for_max; $i+= $second_interval) + $seconds[] = sprintf('%02d', $all_seconds[$i]); + $selected = intval(floor(strftime('%S', $time) / $second_interval) * $second_interval); + $html_result .= '\n"; + } + + if ($display_meridian && !$use_24_hours) { + $html_result .= '\n"; + } + + return $html_result; +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_table.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_table.php new file mode 100644 index 00000000..ece9c8c5 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.html_table.php @@ -0,0 +1,113 @@ + + * Name: html_table
                                                    + * Date: Feb 17, 2003
                                                    + * Purpose: make an html table from an array of data
                                                    + * Input:
                                                    + * - loop = array to loop through + * - cols = number of columns + * - rows = number of rows + * - table_attr = table attributes + * - tr_attr = table row attributes (arrays are cycled) + * - td_attr = table cell attributes (arrays are cycled) + * - trailpad = value to pad trailing cells with + * - vdir = vertical direction (default: "down", means top-to-bottom) + * - hdir = horizontal direction (default: "right", means left-to-right) + * - inner = inner loop (default "cols": print $loop line by line, + * $loop will be printed column by column otherwise) + * + * + * Examples: + *
                                                    + * {table loop=$data}
                                                    + * {table loop=$data cols=4 tr_attr='"bgcolor=red"'}
                                                    + * {table loop=$data cols=4 tr_attr=$colors}
                                                    + * 
                                                    + * @author Monte Ohrt + * @version 1.0 + * @link http://smarty.php.net/manual/en/language.function.html.table.php {html_table} + * (Smarty online manual) + * @param array + * @param Smarty + * @return string + */ +function smarty_function_html_table($params, &$smarty) +{ + $table_attr = 'border="1"'; + $tr_attr = ''; + $td_attr = ''; + $cols = 3; + $rows = 3; + $trailpad = ' '; + $vdir = 'down'; + $hdir = 'right'; + $inner = 'cols'; + + extract($params); + + if (!isset($loop)) { + $smarty->trigger_error("html_table: missing 'loop' parameter"); + return; + } + + $loop_count = count($loop); + if (empty($params['rows'])) { + /* no rows specified */ + $rows = ceil($loop_count/$cols); + } elseif (empty($params['cols'])) { + if (!empty($params['rows'])) { + /* no cols specified, but rows */ + $cols = ceil($loop_count/$rows); + } + } + + $output = "\n"; + + for ($r=0; $r<$rows; $r++) { + $output .= "\n"; + $rx = ($vdir == 'down') ? $r*$cols : ($rows-1-$r)*$cols; + + for ($c=0; $c<$cols; $c++) { + $x = ($hdir == 'right') ? $rx+$c : $rx+$cols-1-$c; + if ($inner!='cols') { + /* shuffle x to loop over rows*/ + $x = floor($x/$cols) + ($x%$cols)*$rows; + } + + if ($x<$loop_count) { + $output .= "" . $loop[$x] . "\n"; + } else { + $output .= "$trailpad\n"; + } + } + $output .= "\n"; + } + $output .= "
                                                    \n"; + + return $output; +} + +function smarty_function_html_table_cycle($name, $var, $no) { + if(!is_array($var)) { + $ret = $var; + } else { + $ret = $var[$no % count($var)]; + } + + return ($ret) ? ' '.$ret : ''; +} + + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.mailto.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.mailto.php new file mode 100644 index 00000000..9273ba39 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.mailto.php @@ -0,0 +1,140 @@ + + * Name: mailto
                                                    + * Date: May 21, 2002 + * Purpose: automate mailto address link creation, and optionally + * encode them.
                                                    + * Input:
                                                    + * - address = e-mail address + * - text = (optional) text to display, default is address + * - encode = (optional) can be one of: + * * none : no encoding (default) + * * javascript : encode with javascript + * * hex : encode with hexidecimal (no javascript) + * - cc = (optional) address(es) to carbon copy + * - bcc = (optional) address(es) to blind carbon copy + * - subject = (optional) e-mail subject + * - newsgroups = (optional) newsgroup(s) to post to + * - followupto = (optional) address(es) to follow up to + * - extra = (optional) extra tags for the href link + * + * Examples: + *
                                                    + * {mailto address="me@domain.com"}
                                                    + * {mailto address="me@domain.com" encode="javascript"}
                                                    + * {mailto address="me@domain.com" encode="hex"}
                                                    + * {mailto address="me@domain.com" subject="Hello to you!"}
                                                    + * {mailto address="me@domain.com" cc="you@domain.com,they@domain.com"}
                                                    + * {mailto address="me@domain.com" extra='class="mailto"'}
                                                    + * 
                                                    + * @link http://smarty.php.net/manual/en/language.function.mailto.php {mailto} + * (Smarty online manual) + * @version 1.2 + * @author Monte Ohrt + * @author credits to Jason Sweat (added cc, bcc and subject functionality) + * @param array + * @param Smarty + * @return string + */ +function smarty_function_mailto($params, &$smarty) +{ + $extra = ''; + extract($params); + + if (empty($address)) { + $smarty->trigger_error("mailto: missing 'address' parameter"); + return; + } + + if (empty($text)) { + $text = $address; + } + + // netscape and mozilla do not decode %40 (@) in BCC field (bug?) + // so, don't encode it. + + $mail_parms = array(); + if (!empty($cc)) { + $mail_parms[] = 'cc='.str_replace('%40','@',rawurlencode($cc)); + } + + if (!empty($bcc)) { + $mail_parms[] = 'bcc='.str_replace('%40','@',rawurlencode($bcc)); + } + + if (!empty($subject)) { + $mail_parms[] = 'subject='.rawurlencode($subject); + } + + if (!empty($newsgroups)) { + $mail_parms[] = 'newsgroups='.rawurlencode($newsgroups); + } + + if (!empty($followupto)) { + $mail_parms[] = 'followupto='.str_replace('%40','@',rawurlencode($followupto)); + } + + $mail_parm_vals = ''; + for ($i=0; $itrigger_error("mailto: 'encode' parameter must be none, javascript or hex"); + return; + } + + if ($encode == 'javascript' ) { + $string = 'document.write(\''.$text.'\');'; + + for ($x=0; $x < strlen($string); $x++) { + $js_encode .= '%' . bin2hex($string[$x]); + } + + return ''; + + } elseif ($encode == 'hex') { + + preg_match('!^(.*)(\?.*)$!',$address,$match); + if(!empty($match[2])) { + $smarty->trigger_error("mailto: hex encoding does not work with extra attributes. Try javascript."); + return; + } + for ($x=0; $x < strlen($address); $x++) { + if(preg_match('!\w!',$address[$x])) { + $address_encode .= '%' . bin2hex($address[$x]); + } else { + $address_encode .= $address[$x]; + } + } + for ($x=0; $x < strlen($text); $x++) { + $text_encode .= '&#x' . bin2hex($text[$x]).';'; + } + + return ''.$text_encode.''; + + } else { + // no encoding + return ''.$text.''; + + } + +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.math.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.math.php new file mode 100644 index 00000000..d2b5d829 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.math.php @@ -0,0 +1,82 @@ + + * Name: math
                                                    + * Purpose: handle math computations in template
                                                    + * @link http://smarty.php.net/manual/en/language.function.math.php {math} + * (Smarty online manual) + * @param array + * @param Smarty + * @return string + */ +function smarty_function_math($params, &$smarty) +{ + // be sure equation parameter is present + if (empty($params['equation'])) { + $smarty->trigger_error("math: missing equation parameter"); + return; + } + + $equation = $params['equation']; + + // make sure parenthesis are balanced + if (substr_count($equation,"(") != substr_count($equation,")")) { + $smarty->trigger_error("math: unbalanced parenthesis"); + return; + } + + // match all vars in equation, make sure all are passed + preg_match_all("!\!(0x)([a-zA-Z][a-zA-Z0-9_]*)!",$equation, $match); + $allowed_funcs = array('int','abs','ceil','cos','exp','floor','log','log10', + 'max','min','pi','pow','rand','round','sin','sqrt','srand','tan'); + foreach($match[2] as $curr_var) { + if (!in_array($curr_var,array_keys($params)) && !in_array($curr_var, $allowed_funcs)) { + $smarty->trigger_error("math: parameter $curr_var not passed as argument"); + return; + } + } + + foreach($params as $key => $val) { + if ($key != "equation" && $key != "format" && $key != "assign") { + // make sure value is not empty + if (strlen($val)==0) { + $smarty->trigger_error("math: parameter $key is empty"); + return; + } + if (!is_numeric($val)) { + $smarty->trigger_error("math: parameter $key: is not numeric"); + return; + } + $equation = preg_replace("/\b$key\b/",$val, $equation); + } + } + + eval("\$smarty_math_result = ".$equation.";"); + + if (empty($params['format'])) { + if (empty($params['assign'])) { + return $smarty_math_result; + } else { + $smarty->assign($params['assign'],$smarty_math_result); + } + } else { + if (empty($params['assign'])){ + printf($params['format'],$smarty_math_result); + } else { + $smarty->assign($params['assign'],sprintf($params['format'],$smarty_math_result)); + } + } +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.popup.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.popup.php new file mode 100644 index 00000000..0eb4fcb3 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.popup.php @@ -0,0 +1,87 @@ + + * Name: popup
                                                    + * Purpose: make text pop up in windows via overlib + * @link http://smarty.php.net/manual/en/language.function.popup.php {popup} + * (Smarty online manual) + * @param array + * @param Smarty + * @return string + */ +function smarty_function_popup($params, &$smarty) +{ + extract($params); + + if (empty($text) && !isset($inarray) && empty($function)) { + $smarty->trigger_error("overlib: attribute 'text' or 'inarray' or 'function' required"); + return false; + } + + if (empty($trigger)) { $trigger = "onmouseover"; } + + $retval = $trigger . '="return overlib(\''.preg_replace(array("!'!","![\r\n]!"),array("\'",'\r'),$text).'\''; + if ($sticky) { $retval .= ",STICKY"; } + if (!empty($caption)) { $retval .= ",CAPTION,'".str_replace("'","\'",$caption)."'"; } + if (!empty($fgcolor)) { $retval .= ",FGCOLOR,'$fgcolor'"; } + if (!empty($bgcolor)) { $retval .= ",BGCOLOR,'$bgcolor'"; } + if (!empty($textcolor)) { $retval .= ",TEXTCOLOR,'$textcolor'"; } + if (!empty($capcolor)) { $retval .= ",CAPCOLOR,'$capcolor'"; } + if (!empty($closecolor)) { $retval .= ",CLOSECOLOR,'$closecolor'"; } + if (!empty($textfont)) { $retval .= ",TEXTFONT,'$textfont'"; } + if (!empty($captionfont)) { $retval .= ",CAPTIONFONT,'$captionfont'"; } + if (!empty($closefont)) { $retval .= ",CLOSEFONT,'$closefont'"; } + if (!empty($textsize)) { $retval .= ",TEXTSIZE,$textsize"; } + if (!empty($captionsize)) { $retval .= ",CAPTIONSIZE,$captionsize"; } + if (!empty($closesize)) { $retval .= ",CLOSESIZE,$closesize"; } + if (!empty($width)) { $retval .= ",WIDTH,$width"; } + if (!empty($height)) { $retval .= ",HEIGHT,$height"; } + if (!empty($left)) { $retval .= ",LEFT"; } + if (!empty($right)) { $retval .= ",RIGHT"; } + if (!empty($center)) { $retval .= ",CENTER"; } + if (!empty($above)) { $retval .= ",ABOVE"; } + if (!empty($below)) { $retval .= ",BELOW"; } + if (isset($border)) { $retval .= ",BORDER,$border"; } + if (isset($offsetx)) { $retval .= ",OFFSETX,$offsetx"; } + if (isset($offsety)) { $retval .= ",OFFSETY,$offsety"; } + if (!empty($fgbackground)) { $retval .= ",FGBACKGROUND,'$fgbackground'"; } + if (!empty($bgbackground)) { $retval .= ",BGBACKGROUND,'$bgbackground'"; } + if (!empty($closetext)) { $retval .= ",CLOSETEXT,'".str_replace("'","\'",$closetext)."'"; } + if (!empty($noclose)) { $retval .= ",NOCLOSE"; } + if (!empty($status)) { $retval .= ",STATUS,'".str_replace("'","\'",$status)."'"; } + if (!empty($autostatus)) { $retval .= ",AUTOSTATUS"; } + if (!empty($autostatuscap)) { $retval .= ",AUTOSTATUSCAP"; } + if (isset($inarray)) { $retval .= ",INARRAY,'$inarray'"; } + if (isset($caparray)) { $retval .= ",CAPARRAY,'$caparray'"; } + if (!empty($capicon)) { $retval .= ",CAPICON,'$capicon'"; } + if (!empty($snapx)) { $retval .= ",SNAPX,$snapx"; } + if (!empty($snapy)) { $retval .= ",SNAPY,$snapy"; } + if (isset($fixx)) { $retval .= ",FIXX,$fixx"; } + if (isset($fixy)) { $retval .= ",FIXY,$fixy"; } + if (!empty($background)) { $retval .= ",BACKGROUND,'$background'"; } + if (!empty($padx)) { $retval .= ",PADX,$padx"; } + if (!empty($pady)) { $retval .= ",PADY,$pady"; } + if (!empty($fullhtml)) { $retval .= ",FULLHTML"; } + if (!empty($frame)) { $retval .= ",FRAME,'$frame'"; } + if (isset($timeout)) { $retval .= ",TIMEOUT,$timeout"; } + if (!empty($function)) { $retval .= ",FUNCTION,'$function'"; } + if (isset($delay)) { $retval .= ",DELAY,$delay"; } + if (!empty($hauto)) { $retval .= ",HAUTO"; } + if (!empty($vauto)) { $retval .= ",VAUTO"; } + $retval .= ');" onmouseout="nd();"'; + + return $retval; +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.popup_init.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.popup_init.php new file mode 100644 index 00000000..e06de696 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.popup_init.php @@ -0,0 +1,39 @@ + + * Name: popup_init
                                                    + * Purpose: initialize overlib + * @link http://smarty.php.net/manual/en/language.function.popup.init.php {popup_init} + * (Smarty online manual) + * @param array + * @param Smarty + * @return string + */ +function smarty_function_popup_init($params, &$smarty) +{ + $zindex = 1000; + + if (!empty($params['zindex'])) { + $zindex = $params['zindex']; + } + + if (!empty($params['src'])) { + return '' . "\n" + . '' . "\n"; + } else { + $smarty->trigger_error("popup_init: missing src parameter"); + } +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.var_dump.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.var_dump.php new file mode 100644 index 00000000..382032c1 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/function.var_dump.php @@ -0,0 +1,20 @@ +',$params,'
                                                '); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.capitalize.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.capitalize.php new file mode 100644 index 00000000..464d5f84 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.capitalize.php @@ -0,0 +1,25 @@ + + * Name: capitalize
                                                + * Purpose: capitalize words in the string + * @link http://smarty.php.net/manual/en/language.modifiers.php#LANGUAGE.MODIFIER.CAPITALIZE + * capitalize (Smarty online manual) + * @param string + * @return string + */ +function smarty_modifier_capitalize($string) +{ + return ucwords($string); +} + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.cat.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.cat.php new file mode 100644 index 00000000..176ee7ae --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.cat.php @@ -0,0 +1,33 @@ + + * Name: cat
                                                + * Date: Feb 24, 2003 + * Purpose: catenate a value to a variable + * Input: string to catenate + * Example: {$var|cat:"foo"} + * @link http://smarty.php.net/manual/en/language.modifier.cat.php cat + * (Smarty online manual) + * @author Monte Ohrt + * @version 1.0 + * @param string + * @param string + * @return string + */ +function smarty_modifier_cat($string, $cat) +{ + return $string . $cat; +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.count_characters.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.count_characters.php new file mode 100644 index 00000000..2fb7c898 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.count_characters.php @@ -0,0 +1,31 @@ + + * Name: count_characteres
                                                + * Purpose: count the number of characters in a text + * @link http://smarty.php.net/manual/en/language.modifier.count.characters.php + * count_characters (Smarty online manual) + * @param string + * @param boolean include whitespace in the character count + * @return integer + */ +function smarty_modifier_count_characters($string, $include_spaces = false) +{ + if ($include_spaces) + return(strlen($string)); + + return preg_match_all("/[^\s]/",$string, $match); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.count_paragraphs.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.count_paragraphs.php new file mode 100644 index 00000000..5f6278fe --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.count_paragraphs.php @@ -0,0 +1,28 @@ + + * Name: count_paragraphs
                                                + * Purpose: count the number of paragraphs in a text + * @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php + * count_paragraphs (Smarty online manual) + * @param string + * @return integer + */ +function smarty_modifier_count_paragraphs($string) +{ + // count \r or \n characters + return count(preg_split('/[\r\n]+/', $string)); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.count_sentences.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.count_sentences.php new file mode 100644 index 00000000..2f3ba65e --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.count_sentences.php @@ -0,0 +1,28 @@ + + * Name: count_sentences + * Purpose: count the number of sentences in a text + * @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php + * count_sentences (Smarty online manual) + * @param string + * @return integer + */ +function smarty_modifier_count_sentences($string) +{ + // find periods with a word before but not after. + return preg_match_all('/[^\s]\.(?!\w)/', $string, $match); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.count_words.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.count_words.php new file mode 100644 index 00000000..a686e4b4 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.count_words.php @@ -0,0 +1,32 @@ + + * Name: count_words
                                                + * Purpose: count the number of words in a text + * @link http://smarty.php.net/manual/en/language.modifier.count.words.php + * count_words (Smarty online manual) + * @param string + * @return integer + */ +function smarty_modifier_count_words($string) +{ + // split text by ' ',\r,\n,\f,\t + $split_array = preg_split('/\s+/',$string); + // count matches that contain alphanumerics + $word_count = preg_grep('/[a-zA-Z0-9\\x80-\\xff]/', $split_array); + + return count($word_count); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.date_format.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.date_format.php new file mode 100644 index 00000000..ab7e9045 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.date_format.php @@ -0,0 +1,43 @@ +_get_plugin_filepath('shared','make_timestamp'); +/** + * Smarty date_format modifier plugin + * + * Type: modifier
                                                + * Name: date_format
                                                + * Purpose: format datestamps via strftime
                                                + * Input:
                                                + * - string: input date string + * - format: strftime format for output + * - default_date: default date if $string is empty + * @link http://smarty.php.net/manual/en/language.modifier.date.format.php + * date_format (Smarty online manual) + * @param string + * @param string + * @param string + * @return string|void + * @uses smarty_make_timestamp() + */ +function smarty_modifier_date_format($string, $format="%b %e, %Y", $default_date=null) +{ + if($string != '') { + return strftime($format, smarty_make_timestamp($string)); + } elseif (isset($default_date) && $default_date != '') { + return strftime($format, smarty_make_timestamp($default_date)); + } else { + return; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.debug_print_var.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.debug_print_var.php new file mode 100644 index 00000000..3158df00 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.debug_print_var.php @@ -0,0 +1,57 @@ + + * Name: debug_print_var
                                                + * Purpose: formats variable contents for display in the console + * @link http://smarty.php.net/manual/en/language.modifier.debug.print.var.php + * debug_print_var (Smarty online manual) + * @param array|object + * @param integer + * @param integer + * @return string + */ +function smarty_modifier_debug_print_var($var, $depth = 0, $length = 40) +{ + $_replace = array("\n"=>'\n', "\r"=>'\r', "\t"=>'\t'); + if (is_array($var)) { + $results = "Array (".count($var).")"; + foreach ($var as $curr_key => $curr_val) { + $return = smarty_modifier_debug_print_var($curr_val, $depth+1, $length); + $results .= "
                                                ".str_repeat(' ', $depth*2)."".strtr($curr_key, $_replace)." => $return"; + } + return $results; + } else if (is_object($var)) { + $object_vars = get_object_vars($var); + $results = "".get_class($var)." Object (".count($object_vars).")"; + foreach ($object_vars as $curr_key => $curr_val) { + $return = smarty_modifier_debug_print_var($curr_val, $depth+1, $length); + $results .= "
                                                ".str_repeat(' ', $depth*2)."$curr_key => $return"; + } + return $results; + } else { + if (empty($var) && $var != "0") { + return 'empty'; + } + if (strlen($var) > $length ) { + $results = substr($var, 0, $length-3).'...'; + } else { + $results = $var; + } + $results = htmlspecialchars($results); + $results = strtr($results, $_replace); + return $results; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.default.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.default.php new file mode 100644 index 00000000..4f1f800a --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.default.php @@ -0,0 +1,31 @@ + + * Name: default
                                                + * Purpose: designate default value for empty variables + * @link http://smarty.php.net/manual/en/language.modifier.default.php + * default (Smarty online manual) + * @param string + * @param string + * @return string + */ +function smarty_modifier_default($string, $default = '') +{ + if (!isset($string) || $string === '') + return $default; + else + return $string; +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.escape.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.escape.php new file mode 100644 index 00000000..dc5ebc6f --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.escape.php @@ -0,0 +1,63 @@ + + * Name: escape
                                                + * Purpose: Escape the string according to escapement type + * @link http://smarty.php.net/manual/en/language.modifier.escape.php + * escape (Smarty online manual) + * @param string + * @param html|htmlall|url|quotes|hex|hexentity|javascript + * @return string + */ +function smarty_modifier_escape($string, $esc_type = 'html') +{ + switch ($esc_type) { + case 'html': + return htmlspecialchars($string, ENT_QUOTES); + + case 'htmlall': + return htmlentities($string, ENT_QUOTES); + + case 'url': + return urlencode($string); + + case 'quotes': + // escape unescaped single quotes + return preg_replace("%(?'\\\\',"'"=>"\\'",'"'=>'\\"',"\r"=>'\\r',"\n"=>'\\n')); + + default: + return $string; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.htmlentities.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.htmlentities.php new file mode 100644 index 00000000..72dcf7de --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.htmlentities.php @@ -0,0 +1,18 @@ + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.indent.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.indent.php new file mode 100644 index 00000000..4a8b81c7 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.indent.php @@ -0,0 +1,27 @@ + + * Name: indent
                                                + * Purpose: indent lines of text + * @link http://smarty.php.net/manual/en/language.modifier.indent.php + * indent (Smarty online manual) + * @param string + * @param integer + * @param string + * @return string + */ +function smarty_modifier_indent($string,$chars=4,$char=" ") +{ + return preg_replace('!^!m',str_repeat($char,$chars),$string); +} + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.lower.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.lower.php new file mode 100644 index 00000000..fecb7168 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.lower.php @@ -0,0 +1,25 @@ + + * Name: lower
                                                + * Purpose: convert string to lowercase + * @link http://smarty.php.net/manual/en/language.modifier.lower.php + * lower (Smarty online manual) + * @param string + * @return string + */ +function smarty_modifier_lower($string) +{ + return strtolower($string); +} + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.nl2br.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.nl2br.php new file mode 100644 index 00000000..2a5f238b --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.nl2br.php @@ -0,0 +1,35 @@ + + * Name: nl2br
                                                + * Date: Feb 26, 2003 + * Purpose: convert \r\n, \r or \n to <
                                                > + * Input:
                                                + * - contents = contents to replace + * - preceed_test = if true, includes preceeding break tags + * in replacement + * Example: {$text|nl2br} + * @link http://smarty.php.net/manual/en/language.modifier.nl2br.php + * nl2br (Smarty online manual) + * @version 1.0 + * @author Monte Ohrt + * @param string + * @return string + */ +function smarty_modifier_nl2br($string) +{ + return nl2br($string); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.rawurlencode.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.rawurlencode.php new file mode 100644 index 00000000..d2d5e813 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.rawurlencode.php @@ -0,0 +1,18 @@ + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.regex_replace.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.regex_replace.php new file mode 100644 index 00000000..a467dfba --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.regex_replace.php @@ -0,0 +1,29 @@ + + * Name: regex_replace
                                                + * Purpose: regular epxression search/replace + * @link http://smarty.php.net/manual/en/language.modifier.regex.replace.php + * regex_replace (Smarty online manual) + * @param string + * @param string|array + * @param string|array + * @return string + */ +function smarty_modifier_regex_replace($string, $search, $replace) +{ + return preg_replace($search, $replace, $string); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.replace.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.replace.php new file mode 100644 index 00000000..590e11b4 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.replace.php @@ -0,0 +1,29 @@ + + * Name: replace
                                                + * Purpose: simple search/replace + * @link http://smarty.php.net/manual/en/language.modifier.replace.php + * replace (Smarty online manual) + * @param string + * @param string + * @param string + * @return string + */ +function smarty_modifier_replace($string, $search, $replace) +{ + return str_replace($search, $replace, $string); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.spacify.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.spacify.php new file mode 100644 index 00000000..bcc5f941 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.spacify.php @@ -0,0 +1,29 @@ + + * Name: spacify
                                                + * Purpose: add spaces between characters in a string + * @link http://smarty.php.net/manual/en/language.modifier.spacify.php + * spacify (Smarty online manual) + * @param string + * @param string + * @return string + */ +function smarty_modifier_spacify($string, $spacify_char = ' ') +{ + return implode($spacify_char, + preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY)); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.string_format.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.string_format.php new file mode 100644 index 00000000..49903137 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.string_format.php @@ -0,0 +1,28 @@ + + * Name: string_format
                                                + * Purpose: format strings via sprintf + * @link http://smarty.php.net/manual/en/language.modifier.string.format.php + * string_format (Smarty online manual) + * @param string + * @param string + * @return string + */ +function smarty_modifier_string_format($string, $format) +{ + return sprintf($format, $string); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.strip.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.strip.php new file mode 100644 index 00000000..fc675582 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.strip.php @@ -0,0 +1,33 @@ + + * Name: strip
                                                + * Purpose: Replace all repeated spaces, newlines, tabs + * with a single space or supplied replacement string.
                                                + * Example: {$var|strip} {$var|strip:" "} + * Date: September 25th, 2002 + * @link http://smarty.php.net/manual/en/language.modifier.strip.php + * strip (Smarty online manual) + * @author Monte Ohrt + * @version 1.0 + * @param string + * @param string + * @return string + */ +function smarty_modifier_strip($text, $replace = ' ') +{ + return preg_replace('!\s+!', $replace, $text); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.strip_tags.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.strip_tags.php new file mode 100644 index 00000000..516a87fc --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.strip_tags.php @@ -0,0 +1,31 @@ + + * Name: strip_tags
                                                + * Purpose: strip html tags from text + * @link http://smarty.php.net/manual/en/language.modifier.strip.tags.php + * strip_tags (Smarty online manual) + * @param string + * @param boolean + * @return string + */ +function smarty_modifier_strip_tags($string, $replace_with_space = true) +{ + if ($replace_with_space) + return preg_replace('!<[^>]*?>!', ' ', $string); + else + return strip_tags($string); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.truncate.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.truncate.php new file mode 100644 index 00000000..775a20e8 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.truncate.php @@ -0,0 +1,43 @@ + + * Name: truncate
                                                + * Purpose: Truncate a string to a certain length if necessary, + * optionally splitting in the middle of a word, and + * appending the $etc string. + * @link http://smarty.php.net/manual/en/language.modifier.truncate.php + * truncate (Smarty online manual) + * @param string + * @param integer + * @param string + * @param boolean + * @return string + */ +function smarty_modifier_truncate($string, $length = 80, $etc = '...', + $break_words = false) +{ + if ($length == 0) + return ''; + + if (strlen($string) > $length) { + $length -= strlen($etc); + if (!$break_words) + $string = preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, $length+1)); + + return substr($string, 0, $length).$etc; + } else + return $string; +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.upper.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.upper.php new file mode 100644 index 00000000..899f6bb9 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.upper.php @@ -0,0 +1,25 @@ + + * Name: upper
                                                + * Purpose: convert string to uppercase + * @link http://smarty.php.net/manual/en/language.modifier.upper.php + * upper (Smarty online manual) + * @param string + * @return string + */ +function smarty_modifier_upper($string) +{ + return strtoupper($string); +} + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.wordwrap.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.wordwrap.php new file mode 100644 index 00000000..fe4407fc --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/modifier.wordwrap.php @@ -0,0 +1,28 @@ + + * Name: wordwrap
                                                + * Purpose: wrap a string of text at a given length + * @link http://smarty.php.net/manual/en/language.modifier.wordwrap.php + * wordwrap (Smarty online manual) + * @param string + * @param integer + * @param string + * @param boolean + * @return string + */ +function smarty_modifier_wordwrap($string,$length=80,$break="\n",$cut=false) +{ + return wordwrap($string,$length,$break,$cut); +} + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/outputfilter.trimwhitespace.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/outputfilter.trimwhitespace.php new file mode 100644 index 00000000..1fa5fe17 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/outputfilter.trimwhitespace.php @@ -0,0 +1,75 @@ + + * Type: outputfilter
                                                + * Name: trimwhitespace
                                                + * Date: Jan 25, 2003
                                                + * Purpose: trim leading white space and blank lines from + * template source after it gets interpreted, cleaning + * up code and saving bandwidth. Does not affect + * <
                                                >
                                                and blocks.
                                                + * Install: Drop into the plugin directory, call + * $smarty->load_filter('output','trimwhitespace'); + * from application. + * @author Monte Ohrt + * @author Contributions from Lars Noschinski + * @version 1.3 + * @param string + * @param Smarty + */ + function smarty_outputfilter_trimwhitespace($source, &$smarty) + { + // Pull out the script blocks + preg_match_all("!]+>.*?!is", $source, $match); + $_script_blocks = $match[0]; + $source = preg_replace("!]+>.*?!is", + '@@@SMARTY:TRIM:SCRIPT@@@', $source); + + // Pull out the pre blocks + preg_match_all("!
                                                .*?
                                                !is", $source, $match); + $_pre_blocks = $match[0]; + $source = preg_replace("!
                                                .*?
                                                !is", + '@@@SMARTY:TRIM:PRE@@@', $source); + + // Pull out the textarea blocks + preg_match_all("!]+>.*?!is", $source, $match); + $_textarea_blocks = $match[0]; + $source = preg_replace("!]+>.*?!is", + '@@@SMARTY:TRIM:TEXTAREA@@@', $source); + + // remove all leading spaces, tabs and carriage returns NOT + // preceeded by a php close tag. + $source = trim(preg_replace('/((?)\n)[\s]+/m', '\1', $source)); + + // replace script blocks + smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:SCRIPT@@@",$_script_blocks, $source); + + // replace pre blocks + smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:PRE@@@",$_pre_blocks, $source); + + // replace textarea blocks + smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:TEXTAREA@@@",$_textarea_blocks, $source); + + return $source; + } + +function smarty_outputfilter_trimwhitespace_replace($search_str, $replace, &$subject) { + $_len = strlen($search_str); + $_pos = 0; + for ($_i=0, $_count=count($replace); $_i<$_count; $_i++) + if (($_pos=strpos($subject, $search_str, $_pos))!==false) + $subject = substr_replace($subject, $replace[$_i], $_pos, $_len); + else + break; + +} + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/shared.escape_special_chars.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/shared.escape_special_chars.php new file mode 100644 index 00000000..72b8a48c --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/shared.escape_special_chars.php @@ -0,0 +1,30 @@ + + * Purpose: used by other smarty functions to escape + * special chars except for already escaped ones + * @param string + * @return string + */ +function smarty_function_escape_special_chars($string) +{ + if(!is_array($string)) { + $string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string); + $string = htmlspecialchars($string); + $string = str_replace(array('%%%SMARTY_START%%%','%%%SMARTY_END%%%'), array('&',';'), $string); + } + return $string; +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/shared.make_timestamp.php b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/shared.make_timestamp.php new file mode 100644 index 00000000..25c7f5c8 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/libs/plugins/shared.make_timestamp.php @@ -0,0 +1,43 @@ + + * Purpose: used by other smarty functions to make a timestamp + * from a string. + * @param string + * @return string + */ +function smarty_make_timestamp($string) +{ + if(empty($string)) { + $string = "now"; + } + $time = strtotime($string); + if (is_numeric($time) && $time != -1) + return $time; + + // is mysql timestamp format of YYYYMMDDHHMMSS? + if (preg_match('/^\d{14}$/', $string)) { + $time = mktime(substr($string,8,2),substr($string,10,2),substr($string,12,2), + substr($string,4,2),substr($string,6,2),substr($string,0,4)); + + return $time; + } + + // couldn't recognize it, try to return a time + $time = (int) $string; + if ($time > 0) + return $time; + else + return time(); +} + +/* vim: set expandtab: */ + +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/misc/smarty_icon.README b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/misc/smarty_icon.README new file mode 100644 index 00000000..bea956fc --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/misc/smarty_icon.README @@ -0,0 +1,6 @@ +Feel free to put the smarty icon on your site. +You can cut-and-paste the following code, be sure +to adjust the path to the image: + + + diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/misc/smarty_icon.gif b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/misc/smarty_icon.gif new file mode 100644 index 00000000..5d519699 Binary files /dev/null and b/buildscripts/PhpDocumentor/phpDocumentor/Smarty-2.6.0/misc/smarty_icon.gif differ diff --git a/buildscripts/PhpDocumentor/phpDocumentor/TutorialHighlightParser.inc b/buildscripts/PhpDocumentor/phpDocumentor/TutorialHighlightParser.inc new file mode 100644 index 00000000..ff7160ce --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/TutorialHighlightParser.inc @@ -0,0 +1,491 @@ + tags output. Using the + * WordParser, the phpDocumentor_TutorialHighlightParser + * retrieves PHP tokens one by one from the array generated by + * {@link WordParser} source retrieval functions + * and then highlights them individually. + * + * It accomplishes this highlighting through the assistance of methods in + * the output Converter passed to its parse() method, and then returns the + * fully highlighted source as a string + * @tutorial tags.example.pkg, tags.filesource.pkg + * @package phpDocumentor + * @subpackage Parsers + * @since 1.3.0 + */ + +/** + * Highlights source code using {@link parse()} + * @package phpDocumentor + * @subpackage Parsers + */ +class phpDocumentor_TutorialHighlightParser extends Parser +{ + /**#@+ @access private */ + /** + * Highlighted source is built up in this string + * @var string + */ + var $_output; + /** + * contents of the current source code line as it is parsed + * @var string + */ + var $_line; + /** + * Used to retrieve highlighted tokens + * @var Converter a descendant of Converter + */ + var $_converter; + /** + * Path to file being highlighted, if this is from a @filesource tag + * @var false|string full path + */ + var $_filesourcepath; + /** + * @var array + */ + var $eventHandlers = array( + TUTORIAL_EVENT_NOEVENTS => 'defaultHandler', + TUTORIAL_EVENT_ITAG => 'defaultHandler', + TUTORIAL_EVENT_ATTRIBUTE => 'attrHandler', + TUTORIAL_EVENT_OPENTAG => 'defaultHandler', + TUTORIAL_EVENT_CLOSETAG => 'defaultHandler', + TUTORIAL_EVENT_ENTITY => 'defaultHandler', + TUTORIAL_EVENT_COMMENT => 'defaultHandler', + TUTORIAL_EVENT_SINGLEQUOTE => 'defaultHandler', + TUTORIAL_EVENT_DOUBLEQUOTE => 'defaultHandler', + ); + /**#@-*/ + + /** + * @uses Converter::SourceLine() encloses {@link $_line} in a + * converter-specific format + */ + function newLineNum() + { + $this->_line .= $this->_converter->flushHighlightCache(); + $this->_output .= $this->_converter->SourceLine($this->_pv_curline + 1, $this->_line, $this->_path); + $this->_line = ''; + } + + /** + * Start the parsing at a certain line number + */ + function setLineNum($num) + { + $this->_wp->linenum = $num; + } + + /** + * Parse a new file + * + * The parse() method is a do...while() loop that retrieves tokens one by + * one from the {@link $_event_stack}, and uses the token event array set up + * by the class constructor to call event handlers. + * + * The event handlers each process the tokens passed to them, and use the + * {@link _addoutput()} method to append the processed tokens to the + * {@link $_line} variable. The word parser calls {@link newLineNum()} + * every time a line is reached. + * + * In addition, the event handlers use special linking functions + * {@link _link()} and its cousins (_classlink(), etc.) to create in-code + * hyperlinks to the documentation for source code elements that are in the + * source code. + * + * @uses setupStates() initialize parser state variables + * @uses configWordParser() pass $parse_data to prepare retrieval of tokens + * @param string + * @param Converter + * @param false|string full path to file with @filesource tag, if this + * is a @filesource parse + * @param false|integer starting line number from {@}source linenum} + * @staticvar integer used for recursion limiting if a handler for + * an event is not found + * @return bool + */ + function parse ($parse_data, &$converter, $filesourcepath = false, $linenum = false) + { + static $endrecur = 0; + $parse_data = str_replace(array("\r\n", "\t"), array("\n", ' '), $parse_data); + $this->_converter = &$converter; + $converter->startHighlight(); + $this->_path = $filesourcepath; + $this->setupStates($parse_data); + + $this->configWordParser(TUTORIAL_EVENT_NOEVENTS); + if ($linenum !== false) $this->setLineNum($linenum); + // initialize variables so E_ALL error_reporting doesn't complain + $pevent = 0; + $word = 0; + + do + { + $lpevent = $pevent; + $pevent = $this->_event_stack->getEvent(); + if ($lpevent != $pevent) + { + $this->_last_pevent = $lpevent; + $this->configWordParser($pevent); + } + $this->_wp->setWhitespace(true); + + $dbg_linenum = $this->_wp->linenum; + $dbg_pos = $this->_wp->getPos(); + $this->_pv_last_word = $word; + $this->_pv_curline = $this->_wp->linenum; + $word = $this->_wp->getWord(); + + if (0)//PHPDOCUMENTOR_DEBUG == true) + { + echo "LAST: "; + echo "|" . $this->_pv_last_word; + echo "|\n"; + echo "PEVENT: " . $this->getParserEventName($pevent) . "\n"; + echo "LASTPEVENT: " . $this->getParserEventName($this->_last_pevent) . "\n"; +// echo "LINE: ".$this->_line."\n"; +// echo "OUTPUT: ".$this->_output."\n"; + echo $dbg_linenum.'-'.$dbg_pos . ": "; + echo '|'.htmlspecialchars($word); + echo "|\n"; + echo "-------------------\n\n\n"; + flush(); + } + if (isset($this->eventHandlers[$pevent])) + { + $handle = $this->eventHandlers[$pevent]; + $this->$handle($word, $pevent); + } else + { + debug('WARNING: possible error, no handler for event number '.$pevent); + if ($endrecur++ == 25) + { + die("FATAL ERROR, recursion limit reached"); + } + } + } while (!($word === false)); + if (strlen($this->_line)) $this->newLineNum(); + return $this->_output; + } + + /**#@+ + * Event Handlers + * + * All Event Handlers use {@link checkEventPush()} and + * {@link checkEventPop()} to set up the event stack and parser state. + * @access private + * @param string|array token value + * @param integer parser event from {@link Parser.inc} + */ + /** + * Most tokens only need highlighting, and this method handles them + */ + function defaultHandler($word, $pevent) + { + if ($word == "\n") { + $this->newLineNum(); + return; + } + if ($this->checkEventPush($word, $pevent)) { + $this->_wp->backupPos($word); + return; + } + $this->_addoutput($word); + $this->checkEventPop($word, $pevent); + } + + /** + * Most tokens only need highlighting, and this method handles them + */ + function attrHandler($word, $pevent) + { + if ($word == "\n") { + $this->newLineNum(); + return; + } + if ($e = $this->checkEventPush($word, $pevent)) { + if ($e == TUTORIAL_EVENT_SINGLEQUOTE || $e == TUTORIAL_EVENT_DOUBLEQUOTE) { + $this->_addoutput($word); + } + return; + } + if ($this->checkEventPop($word, $pevent)) { + $this->_wp->backupPos($word); + return; + } + $this->_addoutput($word); + } + + /**#@+ + * Output Methods + * @access private + */ + /** + * This method adds output to {@link $_line} + * + * If a string with variables like "$test this" is present, then special + * handling is used to allow processing of the variable in context. + * @see _flush_save() + */ + function _addoutput($word, $preformatted = false) + { + $type = + array( + TUTORIAL_EVENT_ATTRIBUTE => 'attribute', + TUTORIAL_EVENT_SINGLEQUOTE => 'attributevalue', + TUTORIAL_EVENT_DOUBLEQUOTE => 'attributevalue', + TUTORIAL_EVENT_CLOSETAG => 'closetag', + TUTORIAL_EVENT_ENTITY => 'entity', + TUTORIAL_EVENT_ITAG => 'itag', + TUTORIAL_EVENT_OPENTAG => 'opentag', + TUTORIAL_EVENT_COMMENT => 'comment', + ); + $a = $this->_event_stack->getEvent(); + if (in_array($a, array_keys($type))) { + $this->_line .= $this->_converter->highlightTutorialSource($type[$a], $word); + } else { + $this->_line .= $this->_converter->flushHighlightCache(); + $this->_line .= $word; + } + } + /**#@-*/ + + /** + * tell the parser's WordParser {@link $wp} to set up tokens to parse words by. + * tokens are word separators. In English, a space or punctuation are examples of tokens. + * In PHP, a token can be a ;, a parenthesis, or even the word "function" + * @param $value integer an event number + * @see WordParser + */ + + function configWordParser($e) + { + $this->_wp->setSeperator($this->tokens[($e + 100)]); + } + /** + * this function checks whether parameter $word is a token for pushing a new event onto the Event Stack. + * @return mixed returns false, or the event number + */ + + function checkEventPush($word,$pevent) + { + $e = false; + if (isset($this->pushEvent[$pevent])) + { + if (isset($this->pushEvent[$pevent][strtolower($word)])) + $e = $this->pushEvent[$pevent][strtolower($word)]; + } + if ($e) + { + $this->_event_stack->pushEvent($e); + return $e; + } else { + return false; + } + } + + /** + * this function checks whether parameter $word is a token for popping the current event off of the Event Stack. + * @return mixed returns false, or the event number popped off of the stack + */ + + function checkEventPop($word,$pevent) + { + if (!isset($this->popEvent[$pevent])) return false; + if (in_array(strtolower($word),$this->popEvent[$pevent])) + { + return $this->_event_stack->popEvent(); + } else { + return false; + } + } + + /** + * Initialize all parser state variables + * @param boolean true if we are highlighting an inline {@}source} tag's + * output + * @param false|string name of class we are going to start from + * @uses $_wp sets to a new {@link phpDocumentor_HighlightWordParser} + */ + function setupStates($parsedata) + { + $this->_output = ''; + $this->_line = ''; + unset($this->_wp); + $this->_wp = new WordParser; + $this->_wp->setup($parsedata); + $this->_event_stack = new EventStack; + $this->_event_stack->popEvent(); + $this->_event_stack->pushEvent(TUTORIAL_EVENT_NOEVENTS); + $this->_pv_linenum = null; + $this->_pv_next_word = false; + } + + /** + * Initialize the {@link $tokenpushEvent, $wordpushEvent} arrays + */ + function phpDocumentor_TutorialHighlightParser() + { + $this->allowableInlineTags = $GLOBALS['_phpDocumentor_inline_tutorial_tags_allowed']; + $this->inlineTagHandlers = array('*' => 'handleDefaultInlineTag'); + $this->tokens[STATE_TUTORIAL_NOEVENTS] = array("\n",'{@', ''); + $this->tokens[STATE_TUTORIAL_ENTITY] = array("\n",';'); + $this->tokens[STATE_TUTORIAL_ATTRIBUTE] = array("\n",'"',"'",'>','/>'); + $this->tokens[STATE_TUTORIAL_DOUBLEQUOTE] = array("\n",'"','&','{@'); + $this->tokens[STATE_TUTORIAL_SINGLEQUOTE] = array("\n","'",'&','{@'); +/**************************************************************/ + + $this->pushEvent[TUTORIAL_EVENT_NOEVENTS] = + array( + "{@" => TUTORIAL_EVENT_ITAG, + '<' => TUTORIAL_EVENT_OPENTAG, + ' TUTORIAL_EVENT_CLOSETAG, + '&' => TUTORIAL_EVENT_ENTITY, + ''); +/**************************************************************/ + + $this->popEvent[TUTORIAL_EVENT_ATTRIBUTE] = array('>','/>'); +/**************************************************************/ + + $this->popEvent[TUTORIAL_EVENT_ITAG] = array('}'); +/**************************************************************/ + } + + function getParserEventName ($value) + { + $lookup = array( + TUTORIAL_EVENT_NOEVENTS => "TUTORIAL_EVENT_NOEVENTS", + TUTORIAL_EVENT_ITAG => "TUTORIAL_EVENT_ITAG", + TUTORIAL_EVENT_OPENTAG => "TUTORIAL_EVENT_OPENTAG", + TUTORIAL_EVENT_ATTRIBUTE => "TUTORIAL_EVENT_ATTRIBUTE", + TUTORIAL_EVENT_CLOSETAG => "TUTORIAL_EVENT_CLOSETAG", + TUTORIAL_EVENT_ENTITY => "TUTORIAL_EVENT_ENTITY", + TUTORIAL_EVENT_COMMENT => "TUTORIAL_EVENT_COMMENT", + TUTORIAL_EVENT_SINGLEQUOTE => "TUTORIAL_EVENT_SINGLEQUOTE", + TUTORIAL_EVENT_DOUBLEQUOTE => "TUTORIAL_EVENT_DOUBLEQUOTE", + ); + if (isset($lookup[$value])) + return $lookup[$value]; + else return $value; + } +} + + +/** starting state */ +define("TUTORIAL_EVENT_NOEVENTS" , 1); +/** currently in starting state */ +define("STATE_TUTORIAL_NOEVENTS" , 101); + +/** used when an {@}inline tag} is found */ +define("TUTORIAL_EVENT_ITAG" , 2); +/** currently parsing an {@}inline tag} */ +define("STATE_TUTORIAL_ITAG" , 102); + +/** used when an open is found */ +define("TUTORIAL_EVENT_OPENTAG" , 3); +/** currently parsing an open */ +define("STATE_TUTORIAL_OPENTAG" , 103); + +/** used when a is found */ +define("TUTORIAL_EVENT_ATTRIBUTE" , 4); +/** currently parsing an open */ +define("STATE_TUTORIAL_ATTRIBUTE" , 104); + +/** used when a close is found */ +define("TUTORIAL_EVENT_CLOSETAG" , 5); +/** currently parsing a close */ +define("STATE_TUTORIAL_CLOSETAG" , 105); + +/** used when an &entity; is found */ +define("TUTORIAL_EVENT_ENTITY" , 6); +/** currently parsing an &entity; */ +define("STATE_TUTORIAL_ENTITY" , 106); + +/** used when a is found */ +define("TUTORIAL_EVENT_COMMENT" , 7); +/** currently parsing a */ +define("STATE_TUTORIAL_COMMENT" , 107); + +/** used when a is found */ +define("TUTORIAL_EVENT_SINGLEQUOTE" , 8); +/** currently parsing a */ +define("STATE_TUTORIAL_SINGLEQUOTE" , 108); + +/** used when a is found */ +define("TUTORIAL_EVENT_DOUBLEQUOTE" , 9); +/** currently parsing a */ +define("STATE_TUTORIAL_DOUBLEQUOTE" , 109); +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/WordParser.inc b/buildscripts/PhpDocumentor/phpDocumentor/WordParser.inc new file mode 100644 index 00000000..e0853370 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/WordParser.inc @@ -0,0 +1,325 @@ + + * @version $Id: WordParser.inc,v 1.1 2005/10/17 18:36:57 jeichorn Exp $ + * @package phpDocumentor + * @subpackage WordParsers + */ +/** + * Retrieves tokens from source code for use by the Parser + * @see Parser + * @author Joshua Eichorn + * @version $Id: WordParser.inc,v 1.1 2005/10/17 18:36:57 jeichorn Exp $ + * @package phpDocumentor + * @subpackage WordParsers + */ +class WordParser +{ + /* + New lines around the world + Macintosh: \r + Unix : \n + Windows : \r\n + */ + + /**#@+ + * @access private + */ + /** + * List of text that separates tokens, used to retrieve tokens + * @var array + */ + var $wordseperators = array(); + + /** + * Position within input of the cursor pointing to the next text to be + * retrieved as a token + * @var integer + */ + var $pos = 0; + + /** + * Size of the input source code + * @var integer + */ + var $size; + + /** + * Source code + * @var string + */ + var $data; + + var $cache; + /** + * Current line number + * @var integer + */ + var $linenum = 0; + /** + * Position the cursor was at the last time line numbers were counted, used + * to guarantee that line numbers are incremented + * @var integer + */ + var $linenumpos = 0; + + /** + * Used for {@}source} tag, contains currently parsed function source + * @var string + */ + var $source = ''; + /** + * flag, determines whether tokens are added to {@link $source} + * @var boolean + */ + var $getsource = false; + + /** + * If true, then white space is returned as a part of tokens, otherwise + * tokens are trimmed + * @var boolean + */ + var $returnWhiteSpace = false; + /**#@-*/ + + /** + * Initialize the WordParser + * @param string source code + */ + function setup(&$input) + { + $this->size = strlen($input); + $this->data = & $input; + $this->pos = 0; + $this->linenum = 0; + $this->linenumpos = 0; + $this->cache = array(); + //$this->run = 0; + //$this->word = WORD_PARSER_RET_WORD; + } + + /** + * Retrieve source code for the last function/method + * @return string + */ + function getSource() + { + $source = $this->source; + $this->source = ''; + $this->getsource = false; + return $source; + } + + /** + * Used to tell the WordParser to start retrieving source code + * @access private + */ + function retrievesource($word = '') + { + $this->source = $word; + $this->getsource = true; + } + + /** + * Retrieve a token from the token list + * + * The {@link Parser} class relies upon this method to retrieve the next + * token. The {@link $wordseperators} array is a collection of strings + * that delineate tokens for the current parser state. $wordseperators + * is set by the parser with a call to {@link Parser::configWordParser()} + * every time a new parser state is reached. + * + * For example, while parsing the source code for a class, the word + * var is a token, and global is not, + * but inside a function, the reverse is true. The parser state + * {@link PARSER_STATE_CLASS} has a token list that includes whitespace, + * code delimiters like ; and {}, and comment/DocBlock indicators + * + * If the whitespace option has been turned off using + * {@link setWhitespace()}, then no whitespace is returned with tokens + * + * {@internal + * In the first segment of the function, the code attempts to find the next + * token. A cache is used to speed repetitious tasks. The $tpos variable + * is used to hold the position of the next token. $npos is used to + * hold the end of the token, and so $npos - $tpos will give the length + * of the token. This is used to allow tokens that contain whitespace, + * should that option be desired. + * + * {@link $data} is of course the string containing the PHP code to be + * parsed, and {@link $pos} is the cursor, or current location within the + * parsed data. + * }} + * @return string|false the next token, an empty string if there are no + * token separators in the $wordseperators array, + * or false if the end of input has been reached + */ + function getWord() + { + //$st = $this->mtime(); + if ($this->size == $this->pos) + { + return false; + } + + // assume, for starting, that the token is from $this->pos to the end + $npos = $this->size; + if (is_array($this->wordseperators)) + { + //$this->wordseperators = array(); + foreach($this->wordseperators as $sep) + { + // cache is set if this separator has been tested + if (isset($this->cache[$sep])) + $tpos = $this->cache[$sep]; + else + $tpos = false; + if ($tpos < $this->pos || !is_int($tpos)) + { + // find the position of the next token separator + $tpos = strpos($this->data,$sep,$this->pos); + } + + // was a token separator found that is closer to the current + // location? + if ( ($tpos < $npos) && !($tpos === false)) + { + //echo trim($sep) . "=$tpos\n"; + // set the length of the token to be from $this->pos to + // the next token separator + $npos = $tpos; + $seplen = strlen($sep); + } + else if (!($tpos === false)) + { + $this->cache[$sep] = $tpos; + } + } + } else { + // no token separators, tell the parser to choose a new state + return ""; + } + + $len = $npos - $this->pos; + if ($len == 0) + { + $len = $seplen; + } + + //$st3 = $this->mtime(); + $word = substr($this->data,$this->pos,$len); + + // Change random other os newlines to the unix one + if ($word == "\r" || $word == "\r\n") + { + $word = "\n"; + } + + if ($this->linenumpos <= $this->pos) + { + $this->linenumpos = $this->pos + $len; + $this->linenum += count(explode("\n",$word)) - 1; + } + + if ($this->getsource) + { + $this->source .= $word; + } + $this->pos = $this->pos + $len; + //$this->word = WORD_PARSER_RET_SEP; + + // Things like // commenats rely on the newline to find their end so im going to have to return them + // never return worthless white space /t ' ' + if ($this->returnWhiteSpace == false) + { + if (strlen(trim($word)) == 0 && $word != "\n") + { + $word = $this->getWord(); + } + } + //$this->time3 = $this->time3 + ($this->mtime() - $st3); + //$this->time = $this->time + ($this->mtime() - $st); + return $word; + } + + + /** + * Returns the current pointer position, or 1 character after the end of the word + */ + function getPos() + { + return $this->pos; + } + + /** + * Unused + * + * {@source} + * @param integer starting position + * @param integer length of block to retrieve + */ + function getBlock($start,$len) + { + return substr($this->data,$start,$len); + } + + /** + * @uses $wordseperators + * @param array array of strings that separate tokens + */ + function setSeperator(&$seps) + { + $this->wordseperators = &$seps; + } + + /** + * Set the internal cursor within the source code + * @param integer + */ + function setPos($pos) + { + $this->pos = $pos; + } + + /** + * Backup to the previous token so that it can be retrieved again in a new + * context. + * + * Occasionally, a word will be passed to an event handler that should be + * handled by another event handler. This method allows that to happen. + * @param string token to back up to + */ + function backupPos($word) + { + if ($this->getsource) $this->source = substr($this->source,0,strlen($this->source) - 1); + $this->pos = $this->pos - strlen($word); + } + + /** + * set parser to return or strip whitespace + * @param boolean + */ + function setWhitespace($val = false) + { + $this->returnWhiteSpace = $val; + } +} +?> diff --git a/buildscripts/PhpDocumentor/phpDocumentor/XMLpackagePageParser.inc b/buildscripts/PhpDocumentor/phpDocumentor/XMLpackagePageParser.inc new file mode 100644 index 00000000..59a3f557 --- /dev/null +++ b/buildscripts/PhpDocumentor/phpDocumentor/XMLpackagePageParser.inc @@ -0,0 +1,554 @@ + + * @since 1.2 + */ +/** when is found */ +define('PHPDOCUMENTOR_PDP_EVENT_PROGRAMLISTING', 600); +/** when is found */ +define('PHPDOCUMENTOR_PDP_STATE_PROGRAMLISTING', 700); +/** when a DocBook is found */ +define('PHPDOCUMENTOR_PDP_EVENT_TAG', 601); +/** when a DocBook is found */ +define('PHPDOCUMENTOR_PDP_STATE_TAG', 701); +/** when is found */ +define('PHPDOCUMENTOR_PDP_EVENT_CDATA', 602); +/** when is found */ +define('PHPDOCUMENTOR_PDP_STATE_CDATA', 702); +/** when tag attributes name="value" are found */ +define('PHPDOCUMENTOR_PDP_EVENT_ATTRIBUTES', 603); +/** when tag attributes name="value" are found */ +define('PHPDOCUMENTOR_PDP_STATE_ATTRIBUTES', 703); +/** when tag attributes name="value" are found */ +define('PHPDOCUMENTOR_PDP_EVENT_ENTITY', 604); +/** when tag attributes name="value" are found */ +define('PHPDOCUMENTOR_PDP_STATE_ENTITY', 704); + +/** + * Used to parse XML DocBook-based tutorials + * @package phpDocumentor + * @subpackage Parsers + * @author Greg Beaver + * @since 1.2 + */ +class XMLPackagePageParser extends Parser +{ + /** @var array */ + var $eventHandlers = array( + PHPDOCUMENTOR_PDP_EVENT_TAG => 'handleTag', + PHPDOCUMENTOR_PDP_EVENT_ATTRIBUTES => 'handleAttributes', + PHPDOCUMENTOR_PDP_EVENT_CDATA => 'handleCData', + PARSER_EVENT_NOEVENTS => 'defaultHandler', + PARSER_EVENT_COMMENTBLOCK => 'ignoreHandler', + PARSER_EVENT_OUTPHP => 'ignoreHandler', + PARSER_EVENT_QUOTE => 'handleQuote', + PHPDOCUMENTOR_PDP_EVENT_ENTITY => 'handleEntity', + ); + + /** + * @var array + */ + var $pars = array(); + + var $refsect1id = false; + var $refsect2id = false; + var $refsect3id = false; + /** + * @var array the tag stack + */ + var $context; + /**#@+ @access private */ + var $_gettoc = false; + var $_toc = array(); + var $_cursection = 0; + /**#@-*/ + /** + * Set up the wordparser + * + * {@source} + * @uses ObjectWordParser + */ + function XMLPackagePageParser() + { + $this->wp = new ObjectWordParser(true); + } + /** + * Parse a new file + * + * @param string $parse_data + * @param array $tutorial for format, see {@link Io::getTutorials()} + * @staticvar integer used for recursion limiting if a handler for an event is not found + * @return bool + * @uses parserTutorial using {@link Publisher::PublishEvent()}, a new tutorial + * is created from the file parsed, and passed to the + * Intermediate Parser + */ + function parse ($parse_data, $tutorial) + { + $tempparse = new ppageParser; + $parse_data = $tempparse->parse($parse_data,true,$tutorial['package'],$tutorial['subpackage'], + basename($tutorial['path']),$tutorial['category'], $tutorial['path']); + unset($tempparse); + static $endrecur = 0; + if (!is_array($parse_data) || count($parse_data) == 0) + { + return false; + } + $this->setupStates(); + + // initialize variables so E_ALL error_reporting doesn't complain + $pevent = 0; + $word = 0; + $this->p_vars['start'] = true; + $this->p_vars['event_stack'] = new EventStack; + + $this->wp->setup($parse_data,false); + $this->wp->setWhitespace(true); + $this->context = array(); + if (isset($this->curtag)) unset($this->curtag); + + do + { + $lpevent = $pevent; + $pevent = $this->p_vars['event_stack']->getEvent(); + if ($lpevent != $pevent) + { + $this->p_vars['last_pevent'] = $lpevent; + } + + if ($this->p_vars['last_pevent'] != $pevent) + { + // its a new event so the word parser needs to be reconfigured + $this->configWordParser($pevent); + } + + + $this->p_vars['last_word'] = $word; + $word = $this->wp->getWord(); + + if (0)//PHPDOCUMENTOR_DEBUG == true) + { + echo "----------------\n"; + echo "LAST: |" . $this->p_vars['last_word'] . "|\n"; +// echo "INDEX: ".$this->p_vars['curpar']."\n"; + echo "PEVENT: " . $this->getParserEventName($pevent) . "\n"; + echo "LASTPEVENT: " . $this->getParserEventName($this->p_vars['last_pevent']) . "\n"; + echo $this->wp->getPos() . " WORD: |$word|\n\n"; +// echo '"'.$this->p_vars['quote_data']."\"\n"; + } + if (isset($this->eventHandlers[$pevent])) + { + $handle = $this->eventHandlers[$pevent]; + if ($word !== false) $this->$handle($word, $pevent); + } else + { + debug('WARNING: possible error, no XMLPackagePageParser handler for event number '.$pevent); + if ($endrecur++ == 25) + { + die("FATAL ERROR, recursion limit reached"); + } + } + $this->p_vars['start'] = false; + } while (!($word === false)); + if (count($this->_toc) && isset($this->p_vars['toc'])) + { + $a = $this->curtag->getTOC($this->p_vars['toc']); + $a->setTOC($this->_toc); + $a->setPath($tutorial['path']); + $this->curtag->setTOC($this->p_vars['toc'],$a); + } + $this->PublishEvent(PHPDOCUMENTOR_EVENT_TUTORIAL,new parserTutorial($this->curtag, $tutorial)); + return $this->curtag; + } + + /**#@+ + * @access private + * @param string|parserInlineTag token + * @param integer parser event + */ + function defaultHandler($word, $pevent) + { + if (is_string($word) && $this->checkEventPush($word, $pevent)) + { + return; + } + } + + function ignoreHandler($word, $pevent) + { + $this->checkEventPop($word, $pevent); + } + + /** + * handler for QUOTE. + * this handler recognizes strings defined with double quotation marks (") and handles them correctly + * in any place that they legally appear in php code + */ + + function handleQuote($word, $pevent) + { + if ($this->p_flags['reset_quote_data'] === true) + { + $this->p_flags['reset_quote_data'] = false; + $this->p_vars['quote_data'] = ""; + } + if (!is_object($word)) $this->checkEventPush( $word, $pevent); + if ($word != "\"") + { + if (is_object($word)) + { + $this->p_vars['quote_data'] = $word; + } + else + { + if (!is_object($this->p_vars['quote_data'])) + $this->p_vars['quote_data'] .= $word; + } + } + if (!is_object($word)) + { + if ($word == '>') + { + if (is_object($this->p_vars['quote_data'])) $this->p_vars['quote_data'] = '{@id '.$this->p_vars['quote_data']->id.'}'; + addErrorDie(PDERROR_UNTERMINATED_ATTRIB,$this->curtag->name,$this->p_vars['attrname'],$this->p_vars['quote_data']); + } + if ($this->checkEventPop($word,$pevent)) + { + $this->p_flags['reset_quote_data'] = true; + } + } + } + + /** + * Handles all XML DocBook tags + */ + function handleTag($word, $pevent) + { + if (isset($this->curtag) && $this->curtag->hasTitle() && $this->_gettoc && $this->_gettoc->name == $this->curtag->name) + { + if (isset($this->_toc[$this->_cursection])) + { + $this->_toc[$this->_cursection]['title'] = $this->curtag->_title; + $this->_cursection++; + } + $this->_gettoc = false; + } + if ($this->p_vars['last_word'] == '<') + { // get tag name + $this->p_flags['begin_tag'] = true; + array_push($this->context,$word); +// if (isset($this->curtag)) debug("pushed ".$this->curtag->name); + if (isset($this->curtag)) + { + array_push($this->pars,$this->curtag); + } + $this->curtag = new parserXMLDocBookTag($word); + } elseif ($this->p_vars['last_word'] == '') + { + $tag = array_pop($this->context); + if ($word == '/>') { + // all is OK + $this->checkEventPop($word, $pevent); + $word = $tag; + } + if ($tag != $word) + { + addErrorDie(PDERROR_UNMATCHED_TUTORIAL_TAG,$tag,$word,$this->curtag->getString()); + } + if (in_array($this->curtag->name, array('refentry', 'refsect1', 'refsect2', 'refsect3'))) + { + if (!isset($this->curtag->_id)) + { + $title = ''; + if (isset($this->curtag->_title)) + { + $title = $this->curtag->_title->getString(); + } + addWarning(PDERROR_NO_DOCBOOK_ID, $this->curtag->name, $title); + } + } + $this->p_flags['begin_tag'] = false; + $curtag = @array_pop($this->pars); +// debug("popped $tag ".$curtag->name.' I am '.$this->curtag->name); + if ($curtag) + { + if ($this->curtag->name == 'refsect1') $this->refsect1id = false; + if ($this->curtag->name == 'refsect2') $this->refsect2id = false; + if ($this->curtag->name == 'refsect3') $this->refsect3id = false; + $curtag->add($this->curtag); +// debug("added ".$this->curtag->name." to ".$curtag->name.' '.$curtag->id); + $this->curtag = $curtag; + } else + { +// debug("here"); + } + } elseif (is_string($word)) + { + if (!($e = $this->checkEventPush($word, $pevent))) + { + if ($this->checkEventPop($word, $pevent)) + { + if ($this->p_flags['begin_tag']) + { + $this->p_vars['event_stack']->pushEvent(PHPDOCUMENTOR_PDP_EVENT_TAG); + $this->p_vars['event_stack']->pushEvent(PHPDOCUMENTOR_PDP_EVENT_CDATA); + $this->p_vars['last_tag'] = array_pop($this->context); + array_push($this->context,$this->p_vars['last_tag']); + $this->p_flags['in_cdata'] = false; + } + return; + } + } else + { + $this->p_flags['start_attr'] = true; + $this->p_flags['end_attr'] = false; + } + } else addErrorDie(PDERROR_CANT_HAVE_INLINE_IN_TAGNAME); + } + + /** + * Handle CData sections + */ + function handleCData($word, $pevent) + { + if ($this->curtag->name == 'refentry' && phpDocumentor_get_class($word) == 'parsertocinlinetag') + { + $this->p_vars['toc'] = $this->curtag->getTOC(); + } + if (is_string($word) && !$this->p_flags['in_cdata']) + { + if ($this->checkEventPop($word, $pevent)) + { + return; + } + if ($this->checkEventPush($word, $pevent)) + { + return; + } + } + if ($word == 'curtag->startCData(); + $this->p_flags['in_cdata'] = true; + } elseif ($this->p_flags['in_cdata'] && $word == ']]>') + { + $this->curtag->endCData(); + $this->p_flags['in_cdata'] = false; + } else + { + if ($this->p_flags['in_cdata']) + $this->curtag->addCData($word); + else + $this->curtag->add($word); + } + } + + /** + * Handle Entities like ” + */ + function handleEntity($word, $pevent) + { + if (!$word) + { + if (!isset($this->p_vars['entity_name'])) + $this->p_vars['entity_name'] = ''; + addErrorDie(PDERROR_UNTERMINATED_ENTITY,$this->p_vars['entity_name']); + } + $e = $this->checkEventPop($word, $pevent); + if ($word && !$e) $this->p_vars['entity_name'] = $word; + if ($e) + { + $entity = new parserEntity($this->p_vars['entity_name']); + unset($this->p_vars['entity_name']); + $this->curtag->add($entity); + } + } + + /** + * Handle Tag attributes name="value" + */ + function handleAttributes($word, $pevent) + { + if ($this->checkEventPush($word, $pevent)) return; + if ($word == '=') + { + $this->p_flags['start_attr'] = false; + $this->p_vars['end_attr'] = true; + } else + { + if ($this->p_flags['start_attr']) + { + $this->p_vars['attrname'] = $word; + } else + { + if (isset($this->p_vars['attrname'])) + { + $value = $this->p_vars['quote_data']; + if (phpDocumentor_get_class($value) == 'parseridinlinetag') + { // "inherit" the parent section's id, so + // + // ... + // + // ... + // + // + $a = ($this->refsect1id ? $this->refsect1id . '.' : ''); + $a .= ($this->refsect2id ? $this->refsect2id . '.' : ''); + $a .= ($this->refsect3id ? $this->refsect3id . '.' : ''); + if ($this->curtag->name == 'refsect1') + { + $this->refsect1id = $value->id; + } + if ($this->curtag->name == 'refsect2') + { + $this->refsect2id = $value->id; + } + if ($this->curtag->name == 'refsect3') + { + $this->refsect3id = $value->id; + } +// debug($value->id.' is now '.$a.$value->id); + $value->id = $a . $value->id; + if ($value->id != '') + { + if (isset($this->_toc[$this->_cursection])) + { + $this->_cursection++; + } + $this->_toc[$this->_cursection]['id'] = $value; + $this->_toc[$this->_cursection]['tag'] = new parserXMLDocBookTag($this->curtag->name); +// debug("set gettoc to ".$this->curtag->name .' '. $value->id); + $this->_gettoc = $this->curtag; + } + } + $this->curtag->addAttribute($this->p_vars['attrname'],$value); + unset($this->p_vars['attrname']); + $this->p_flags['end_attr'] = false; + } + } + } + if (is_string($word) && $this->checkEventPop($word, $pevent)) + { + $this->p_flags['start_attr'] = true; + $this->p_flags['end_attr'] = false; + $this->wp->setPos($this->wp->getPos() - strlen($word)); + } + } + /**#@-*/ + + /** + * setup the parser tokens, and the pushEvent/popEvent arrays + * @see $tokens, $pushEvent, $popEvent + */ + + function setupStates() + { + $this->_gettoc = false; + $this->_toc = array(); + $this->_cursection = 0; + if (isset($this->p_vars['toc'])) unset($this->p_vars['toc']); + + $this->tokens[STATE_NOEVENTS] = array('tokens[STATE_COMMENTBLOCK] = array('-->'); + $this->tokens[STATE_OUTPHP] = array('?>'); + $this->tokens[STATE_QUOTE] = array("\\\"","\\\\","\"",'>'); + $this->tokens[STATE_ESCAPE] = false;// this tells the word parser to just cycle + $this->tokens[PHPDOCUMENTOR_PDP_STATE_TAG] = array('>',' ','/>'); + $this->tokens[PHPDOCUMENTOR_PDP_STATE_CDATA] = array('&','"); +########################## + $this->pushEvent[PARSER_EVENT_QUOTE] = + array( + "\\" => PARSER_EVENT_ESCAPE + ); + $this->popEvent[PARSER_EVENT_QUOTE] = array("\""); +########################## + + $this->popEvent[PARSER_EVENT_OUTPHP] = array("?>"); +########################## + + $this->popEvent[PHPDOCUMENTOR_PDP_EVENT_ENTITY] = array(";"); +########################## + + $this->pushEvent[PHPDOCUMENTOR_PDP_EVENT_CDATA] = + array( + "<" => PHPDOCUMENTOR_PDP_EVENT_TAG, + ' + +
                                                +Last modified: $Date: 2005/10/17 18:15:16 $
                                                +Revision: $Revision: 1.1 $
                                                +
                                                + + + + + diff --git a/buildscripts/PhpDocumentor/poweredbyphpdoc.gif b/buildscripts/PhpDocumentor/poweredbyphpdoc.gif new file mode 100644 index 00000000..80e47255 Binary files /dev/null and b/buildscripts/PhpDocumentor/poweredbyphpdoc.gif differ diff --git a/buildscripts/PhpDocumentor/scripts/add_cvs.php b/buildscripts/PhpDocumentor/scripts/add_cvs.php new file mode 100644 index 00000000..2dfcd656 --- /dev/null +++ b/buildscripts/PhpDocumentor/scripts/add_cvs.php @@ -0,0 +1,153 @@ + + * @copyright Copyright 2003, Greg Beaver + * @version 1.0 + */ +/**#@+ + * phpDocumentor include files. If you don't have phpDocumentor, go get it! + * Your php life will be changed forever + */ +$dir = realpath(dirname(__FILE__).'/..'); +require_once("$dir/phpDocumentor/common.inc.php"); +require_once("$dir/phpDocumentor/Io.inc"); +/**#@-*/ + +/** +* Physical location on this computer of the package to parse +* @global string $cvsadd_directory +*/ +$cvsadd_directory = realpath('.'); +/** +* Comma-separated list of files and directories to ignore +* +* This uses wildcards * and ? to remove extra files/directories that are +* not part of the package or release +* @global string $ignore +*/ +$ignore = array('CVS/'); + +/****************************************************************************** +* Don't change anything below here unless you're adventuresome * +*******************************************************************************/ + +/** + * @global Io $files + */ +$files = new Io; + +$allfiles = $files->dirList($cvsadd_directory); +/**#@+ + * Sorting functions for the file list + * @param string + * @param string + */ +function sortfiles($a, $b) +{ + return strnatcasecmp($a['file'],$b['file']); +} + +function mystrucsort($a, $b) +{ + if (is_numeric($a) && is_string($b)) return 1; + if (is_numeric($b) && is_string($a)) return -1; + if (is_numeric($a) && is_numeric($b)) + { + if ($a > $b) return 1; + if ($a < $b) return -1; + if ($a == $b) return 0; + } + return strnatcasecmp($a,$b); +} +/**#@-*/ + +$struc = array(); +foreach($allfiles as $file) +{ + if ($files->checkIgnore(basename($file),dirname($file),$ignore, false)) + { +// print 'Ignoring '.$file."
                                                \n"; + continue; + } + $path = substr(dirname($file),strlen(str_replace('\\','/',realpath($cvsadd_directory)))+1); + if (!$path) $path = '/'; + $file = basename($file); + $ext = array_pop(explode('.',$file)); + if (strlen($ext) == strlen($file)) $ext = ''; + $struc[$path][] = array('file' => $file,'ext' => $ext); +} +uksort($struc,'strnatcasecmp'); +foreach($struc as $key => $ind) +{ + usort($ind,'sortfiles'); + $struc[$key] = $ind; +} +$tempstruc = $struc; +$struc = array('/' => $tempstruc['/']); +$bv = 0; +foreach($tempstruc as $key => $ind) +{ + $save = $key; + if ($key != '/') + { + $struc['/'] = setup_dirs($struc['/'], explode('/',$key), $tempstruc[$key]); + } +} +uksort($struc['/'],'mystrucsort'); +/** + * Recursively add files to cvs + * @param array the sorted directory structure + */ +function addToCVS($struc) +{ + foreach($struc as $dir => $files) + { + if ($dir === '/') + { + print 'processing '.$dir . "\n"; + addToCVS($struc[$dir]); + return; + } else + { + if (!isset($files['file'])) + { + print 'adding '.$dir . "\n"; + system('cvs add '.$dir); + chdir($dir); + addToCVS($files); + chdir('..'); + } else + { + print 'adding '.$files['file'] . "\n"; + system('cvs add '.$files['file']); + system('cvs commit -m "" '.$files['file']); + } + } + } +} +addToCVS($struc); +print "\n".'done'; +?> \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/scripts/create_examples.php b/buildscripts/PhpDocumentor/scripts/create_examples.php new file mode 100644 index 00000000..d8b3b8ff --- /dev/null +++ b/buildscripts/PhpDocumentor/scripts/create_examples.php @@ -0,0 +1,66 @@ + 'HTML:default:default', + $output_directory.'/docs/phpdoc_l0l33t' => 'HTML:default:l0l33t', + $output_directory.'/docs/phpdoc_phpdoc_de' => 'HTML:default:phpdoc.de', + $output_directory.'/docs/phpdoc_DOM_default' => 'HTML:default:DOM/default', + $output_directory.'/docs/phpdoc_DOM_l0l33t' => 'HTML:default:DOM/l0l33t', + $output_directory.'/docs/phpdoc_DOM_phpdoc_de' => 'HTML:default:DOM/phpdoc.de', + $output_directory.'/docs/phpdoc_smarty_default' => 'HTML:Smarty:default' + $output_directory.'/docs/phpdoc_pdf_default' => 'PDF:default:default' + $output_directory.'/docs/phpdoc_chm_default' => 'CHM:default:default' + ); + +foreach($output as $output => $template) +{ + passthru("./phpdoc -d /home/jeichorn/phpdoc -dn $base_package -ti \"$title\" -td $template -t $output"); +} diff --git a/buildscripts/PhpDocumentor/scripts/create_package.xml.php b/buildscripts/PhpDocumentor/scripts/create_package.xml.php new file mode 100644 index 00000000..2ef0fd2c --- /dev/null +++ b/buildscripts/PhpDocumentor/scripts/create_package.xml.php @@ -0,0 +1,204 @@ +setOptions( +array('baseinstalldir' => 'PhpDocumentor', +'version' => '1.3.0RC4', +'packagedirectory' => $packagedir, +'state' => 'beta', +'filelistgenerator' => 'cvs', +'notes' => 'PHP 5 support and more, fix bugs + +This will be the last release in the 1.x series. 2.0 is next + +Features added to this release include: + + * Full PHP 5 support, phpDocumentor both runs in and parses Zend Engine 2 + language constructs. Note that you must be running phpDocumentor in + PHP 5 in order to parse PHP 5 code + * XML:DocBook/peardoc2:default converter now beautifies the source using + PEAR\'s XML_Beautifier if available + * inline {@example} tag - this works just like {@source} except that + it displays the contents of another file. In tutorials, it works + like + * customizable README/INSTALL/CHANGELOG files + * phpDocumentor tries to run .ini files out of the current directory + first, to allow you to put them anywhere you want to + * multi-national characters are now allowed in package/subpackage names + * images in tutorials with the tag + * un-modified output with + * html/xml source highlighting with + +From both Windows and Unix, both the command-line version +of phpDocumentor and the web interface will work +out of the box by using command phpdoc - guaranteed :) + +WARNING: in order to use the web interface through PEAR, you must set your +data_dir to a subdirectory of your document root. + +$ pear config-set data_dir /path/to/public_html/pear + +on Windows with default apache setup, it might be + +C:\> pear config-set data_dir "C:\Program Files\Apache\htdocs\pear" + +After this, install/upgrade phpDocumentor + +$ pear upgrade phpDocumentor + +and you can browse to: + +http://localhost/pear/PhpDocumentor/ + +for the web interface + +------ +WARNING: The PDF Converter will not work in PHP5. The PDF library that it relies upon +segfaults with the simplest of files. Generation still works great in PHP4 +------ + +- WARNING: phpDocumentor installs phpdoc in the + scripts directory, and this will conflict with PHPDoc, + you can\'t have both installed at the same time +- Switched to Smarty 2.6.0, now it will work in PHP 5. Other + changes made to the code to make it work in PHP 5, including parsing + of private/public/static/etc. access modifiers +- fixed these bugs: + [ not entered ] XMLDocBookpeardoc2 beautifier removes comments + [ 896444 ] Bad line numbers + [ 937235 ] duplicated /** after abstract method declaration + [ 962319 ] Define : don\'t show the assigned value + [ 977674 ] Parser error + [ 989258 ] wrong interfaces parsing + [ 1150809 ] Infinite loop when class extends itself + [ 1151196 ] PHP Fatal error: Cannot re-assign $this + [ 1151650 ] UTF8 decoding for DocBook packages + [ 1152781 ] PHP_NOTICE: Uninitialized string offset in ParserDescCleanup + [ 1153593 ] string id="...." in tutorials + [ 1164253 ] Inherited Class Constants are not displayed + [ 1171583 ] CHM wrong filesource + [ 1180200 ] HighlightParser does not handle Heredoc Blocks. + [ 1202772 ] missing parentheses in Parser.inc line 946 + [ 1203445 ] Call to a member function on a non-object in Parser.inc + [ 1203451 ] array to string conversion notice in InlineTags.inc +- fixed these bugs reported in PEAR: + Bug #2288: Webfrontend ignores more than one dir in "Files to ignore" + Bug #5011: PDF generation warning on uksort +', +'package' => 'PhpDocumentor', +'dir_roles' => array( + 'Documentation' => 'doc', + 'Documentation/tests' => 'test', + 'docbuilder' => 'data', + 'HTML_TreeMenu-1.1.2' => 'data', + 'tutorials' => 'doc', + 'phpDocumentor/Converters/CHM/default/templates/default/templates_c' => 'data', + 'phpDocumentor/Converters/PDF/default/templates/default/templates_c' => 'data', + 'phpDocumentor/Converters/HTML/frames/templates/default/templates_c' => 'data', + 'phpDocumentor/Converters/HTML/frames/templates/l0l33t/templates_c' => 'data', + 'phpDocumentor/Converters/HTML/frames/templates/phpdoc.de/templates_c' => 'data', + 'phpDocumentor/Converters/HTML/frames/templates/phphtmllib/templates_c' => 'data', + 'phpDocumentor/Converters/HTML/frames/templates/phpedit/templates_c' => 'data', + 'phpDocumentor/Converters/HTML/frames/templates/earthli/templates_c' => 'data', + 'phpDocumentor/Converters/HTML/frames/templates/DOM/default/templates_c' => 'data', + 'phpDocumentor/Converters/HTML/frames/templates/DOM/l0l33t/templates_c' => 'data', + 'phpDocumentor/Converters/HTML/frames/templates/DOM/phpdoc.de/templates_c' => 'data', + 'phpDocumentor/Converters/HTML/frames/templates/DOM/phphtmllib/templates_c' => 'data', + 'phpDocumentor/Converters/HTML/frames/templates/DOM/earthli/templates_c' => 'data', + 'phpDocumentor/Converters/HTML/Smarty/templates/default/templates_c' => 'data', + 'phpDocumentor/Converters/HTML/Smarty/templates/PHP/templates_c' => 'data', + 'phpDocumentor/Converters/HTML/Smarty/templates/HandS/templates_c' => 'data', + 'phpDocumentor/Converters/XML/DocBook/peardoc2/templates/default/templates_c' => 'data', + ), +'simpleoutput' => true, +'exceptions' => + array( + 'index.html' => 'data', + 'README' => 'doc', + 'ChangeLog' => 'doc', + 'PHPLICENSE.txt' => 'doc', + 'poweredbyphpdoc.gif' => 'data', + 'INSTALL' => 'doc', + 'FAQ' => 'doc', + 'Authors' => 'doc', + 'Release-1.2.0beta1' => 'doc', + 'Release-1.2.0beta2' => 'doc', + 'Release-1.2.0beta3' => 'doc', + 'Release-1.2.0rc1' => 'doc', + 'Release-1.2.0rc2' => 'doc', + 'Release-1.2.0' => 'doc', + 'Release-1.2.1' => 'doc', + 'Release-1.2.2' => 'doc', + 'Release-1.2.3' => 'doc', + 'Release-1.2.3.1' => 'doc', + 'Release-1.3.0' => 'doc', + 'pear-phpdoc' => 'script', + 'pear-phpdoc.bat' => 'script', + 'HTML_TreeMenu-1.1.2/TreeMenu.php' => 'php', + 'phpDocumentor/Smarty-2.6.0/libs/debug.tpl' => 'php', + 'new_phpdoc.php' => 'data', + 'phpdoc.php' => 'data', + ), +'ignore' => + array('package.xml', + "$packagedir/phpdoc", + 'phpdoc.bat', + 'LICENSE', + '*templates/PEAR/*', + 'phpDocumentor/Smarty-2.5.0/*', + '*CSV*', + 'makedocs.ini', + 'publicweb-PEAR-1.2.1.patch.txt', + ), +'installas' => + array('pear-phpdoc' => 'phpdoc', + 'pear-phpdoc.bat' => 'phpdoc.bat', + 'user/pear-makedocs.ini' => 'user/makedocs.ini', + ), +'installexceptions' => array('pear-phpdoc' => '/', 'pear-phpdoc.bat' => '/', 'scripts/makedoc.sh' => '/'), +)); +if (PEAR::isError($e)) { + echo $e->getMessage(); + exit; +} +$test->addPlatformException('pear-phpdoc.bat', 'windows'); +$test->addDependency('php', '4.1.0', 'ge', 'php'); +// optional dep for peardoc2 converter +$test->addDependency('XML_Beautifier', '1.1', 'ge', 'pkg', true); +// replace @PHP-BIN@ in this file with the path to php executable! pretty neat +$test->addReplacement('pear-phpdoc', 'pear-config', '@PHP-BIN@', 'php_bin'); +$test->addReplacement('pear-phpdoc.bat', 'pear-config', '@PHP-BIN@', 'php_bin'); +$test->addReplacement('pear-phpdoc.bat', 'pear-config', '@BIN-DIR@', 'bin_dir'); +$test->addReplacement('pear-phpdoc.bat', 'pear-config', '@PEAR-DIR@', 'php_dir'); +$test->addReplacement('pear-phpdoc.bat', 'pear-config', '@DATA-DIR@', 'data_dir'); +$test->addReplacement('docbuilder/includes/utilities.php', 'pear-config', '@DATA-DIR@', 'data_dir'); +$test->addReplacement('docbuilder/builder.php', 'pear-config', '@DATA-DIR@', 'data_dir'); +$test->addReplacement('docbuilder/file_dialog.php', 'pear-config', '@DATA-DIR@', 'data_dir'); +$test->addReplacement('docbuilder/file_dialog.php', 'pear-config', '@WEB-DIR@', 'data_dir'); +$test->addReplacement('docbuilder/actions.php', 'pear-config', '@WEB-DIR@', 'data_dir'); +$test->addReplacement('docbuilder/top.php', 'pear-config', '@DATA-DIR@', 'data_dir'); +$test->addReplacement('docbuilder/config.php', 'pear-config', '@DATA-DIR@', 'data_dir'); +$test->addReplacement('docbuilder/config.php', 'pear-config', '@WEB-DIR@', 'data_dir'); +$test->addReplacement('phpDocumentor/Setup.inc.php', 'pear-config', '@DATA-DIR@', 'data_dir'); +$test->addReplacement('phpDocumentor/Converter.inc', 'pear-config', '@DATA-DIR@', 'data_dir'); +$test->addReplacement('phpDocumentor/common.inc.php', 'package-info', '@VER@', 'version'); +$test->addReplacement('phpDocumentor/IntermediateParser.inc', 'package-info', '@VER@', 'version'); +$test->addReplacement('user/pear-makedocs.ini', 'pear-config', '@PEAR-DIR@', 'php_dir'); +$test->addReplacement('user/pear-makedocs.ini', 'pear-config', '@DOC-DIR@', 'doc_dir'); +$test->addReplacement('user/pear-makedocs.ini', 'package-info', '@VER@', 'version'); +$test->addRole('inc', 'php'); +$test->addRole('sh', 'script'); +if (isset($_GET['make'])) { + $test->writePackageFile(); +} else { + $test->debugPackageFile(); +} +if (!isset($_GET['make'])) { + echo 'Make this file'; +} +?> \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/scripts/makedoc.sh b/buildscripts/PhpDocumentor/scripts/makedoc.sh new file mode 100644 index 00000000..83c3bcc0 --- /dev/null +++ b/buildscripts/PhpDocumentor/scripts/makedoc.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# $Id: makedoc.sh,v 1.1 2005/10/17 18:37:43 jeichorn Exp $ + +#/** +# * makedoc - PHPDocumentor script to save your settings +# * +# * Put this file inside your PHP project homedir, edit its variables and run whenever you wants to +# * re/make your project documentation. +# * +# * The version of this file is the version of PHPDocumentor it is compatible. +# * +# * It simples run phpdoc with the parameters you set in this file. +# * NOTE: Do not add spaces after bash variables. +# * +# * @copyright makedoc.sh is part of PHPDocumentor project {@link http://freshmeat.net/projects/phpdocu/} and its LGPL +# * @author Roberto Berto +# * @version Release-1.1.0 +# */ + + +############################## +# should be edited +############################## + +#/** +# * title of generated documentation, default is 'Generated Documentation' +# * +# * @var string TITLE +# */ +TITLE="Your Project Documentation" + +#/** +# * name to use for the default package. If not specified, uses 'default' +# * +# * @var string PACKAGES +# */ +PACKAGES="yourProject" + +#/** +# * name of a directory(s) to parse directory1,directory2 +# * $PWD is the directory where makedoc.sh +# * +# * @var string PATH_PROJECT +# */ +PATH_PROJECT=$PWD + +#/** +# * path of PHPDoc executable +# * +# * @var string PATH_PHPDOC +# */ +PATH_PHPDOC=~/phpdoc/phpdoc + +#/** +# * where documentation will be put +# * +# * @var string PATH_DOCS +# */ +PATH_DOCS=$PWD/docs + +#/** +# * what outputformat to use (html/pdf) +# * +# * @var string OUTPUTFORMAT +# */ +OUTPUTFORMAT=HTML + +#/** +# * converter to be used +# * +# * @var string CONVERTER +# */ +CONVERTER=Smarty + +#/** +# * template to use +# * +# * @var string TEMPLATE +# */ +TEMPLATE=default + +#/** +# * parse elements marked as private +# * +# * @var bool (on/off) PRIVATE +# */ +PRIVATE=off + +# make documentation +$PATH_PHPDOC -d $PATH_PROJECT -t $PATH_DOCS -ti "$TITLE" -dn $PACKAGES \ +-o $OUTPUTFORMAT:$CONVERTER:$TEMPLATE -pp $PRIVATE + + +# vim: set expandtab : diff --git a/buildscripts/PhpDocumentor/scripts/tokenizer_test.php b/buildscripts/PhpDocumentor/scripts/tokenizer_test.php new file mode 100644 index 00000000..2b5ca25e --- /dev/null +++ b/buildscripts/PhpDocumentor/scripts/tokenizer_test.php @@ -0,0 +1,59 @@ +package_index)) + foreach(\$this->all_packages as \$key => \$val) + { + if (isset(\$this->pkg_elements[\$key])) + { + if (!isset(\$start)) \$start = \$key; + \$this->package_index[] = array('link' => \"li_\$key.html\", 'title' => \$key); + } + } + \$templ = new Smarty; + \$templ->template_dir = \$this->smarty_dir . PATH_DELIMITER . 'templates'; + \$templ->compile_dir = \$this->smarty_dir . PATH_DELIMITER . 'templates_c'; + \$templ->config_dir = \$this->smarty_dir . PATH_DELIMITER . 'configs'; + \$templ->assign(\"packageindex\",\$this->package_index); + \$templ->assign(\"phpdocversion\",PHPDOCUMENTOR_VER); + \$templ->assign(\"phpdocwebsite\",PHPDOCUMENTOR_WEBSITE); + \$templ->assign(\"package\",\$this->package); + \$templ->assign(\"subdir\",''); + return \$templ; + } +?> +"; +$tokens = token_get_all($file); + +$nl_check = array(T_WHITESPACE,T_ENCAPSED_AND_WHITESPACE,T_COMMENT,T_DOC_COMMENT,T_OPEN_TAG,T_CLOSE_TAG,T_INLINE_HTML); +print '
                                                ';
                                                +$line = 0;
                                                +foreach($tokens as $key => $val)
                                                +{
                                                +	if (is_array($val))
                                                +	{
                                                +		// seeing if we can get line numbers out of the beast
                                                +		if (in_array($val[0],$nl_check))
                                                +		{
                                                +			$line+=substr_count($val[1],"\n");
                                                +		}
                                                +		echo token_name($val[0])." => ".htmlentities($val[1])."\n";
                                                +	}
                                                +	else
                                                +	{
                                                +		echo "*** $val\n";
                                                +	}
                                                +}
                                                +echo "$line\n";
                                                +print '
                                                '; +?> diff --git a/buildscripts/PhpDocumentor/user/default.ini b/buildscripts/PhpDocumentor/user/default.ini new file mode 100644 index 00000000..4915f607 --- /dev/null +++ b/buildscripts/PhpDocumentor/user/default.ini @@ -0,0 +1,98 @@ +;; phpDocumentor parse configuration file +;; +;; This file is designed to cut down on repetitive typing on the command-line or web interface +;; You can copy this file to create a number of configuration files that can be used with the +;; command-line switch -c, as in phpdoc -c default.ini or phpdoc -c myini.ini. The web +;; interface will automatically generate a list of .ini files that can be used. +;; +;; default.ini is used to generate the online manual at http://www.phpdoc.org/docs +;; +;; ALL .ini files must be in the user subdirectory of phpDocumentor with an extension of .ini +;; +;; Copyright 2002, Greg Beaver +;; +;; WARNING: do not change the name of any command-line parameters, phpDocumentor will ignore them + +[Parse Data] +;; title of all the documentation +;; legal values: any string +title = phpDocumentor 1.3.0 Manual + +;; parse files that start with a . like .bash_profile +;; legal values: true, false +hidden = false + +;; show elements marked @access private in documentation by setting this to on +;; legal values: on, off +parseprivate = off + +;; parse with javadoc-like description (first sentence is always the short description) +;; legal values: on, off +javadocdesc = off + +;; add any custom @tags separated by commas here +;; legal values: any legal tagname separated by commas. +;customtags = mytag1,mytag2 + +;; This is only used by the XML:DocBook/peardoc2 converter +defaultcategoryname = Documentation + +;; what is the main package? +;; legal values: alphanumeric string plus - and _ +defaultpackagename = phpDocumentor + +;; output any parsing information? set to on for cron jobs +;; legal values: on +;quiet = on + +;; parse a PEAR-style repository. Do not turn this on if your project does +;; not have a parent directory named "pear" +;; legal values: on/off +;pear = on + +;; where should the documentation be written? +;; legal values: a legal path +target = /home/cellog/output + +;; Which files should be parsed out as special documentation files, such as README, +;; INSTALL and CHANGELOG? This overrides the default files found in +;; phpDocumentor.ini (this file is not a user .ini file, but the global file) +readmeinstallchangelog = README, INSTALL, CHANGELOG, NEWS, FAQ, LICENSE + +;; limit output to the specified packages, even if others are parsed +;; legal values: package names separated by commas +;packageoutput = package1,package2 + +;; comma-separated list of files to parse +;; legal values: paths separated by commas +;filename = /path/to/file1,/path/to/file2,fileincurrentdirectory + +;; comma-separated list of directories to parse +;; legal values: directory paths separated by commas +;directory = /path1,/path2,.,..,subdirectory +;directory = /home/jeichorn/cvs/pear +directory = /home/cellog/phpdoc + +;; template base directory (the equivalent directory of /phpDocumentor) +;templatebase = /path/to/my/templates + +;; directory to find any example files in through @example and {@example} tags +;examplesdir = /path/to/my/templates + +;; comma-separated list of files, directories or wildcards ? and * (any wildcard) to ignore +;; legal values: any wildcard strings separated by commas +;ignore = /path/to/ignore*,*list.php,myfile.php,subdirectory/ +ignore = templates_c/,*HTML/default/*,spec/ + +;; comma-separated list of Converters to use in outputformat:Convertername:templatedirectory format +;; legal values: HTML:frames:default,HTML:frames:l0l33t,HTML:frames:phpdoc.de,HTML:frames:phphtmllib, +;; HTML:frames:earthli, +;; HTML:frames:DOM/default,HTML:frames:DOM/l0l33t,HTML:frames:DOM/phpdoc.de, +;; HTML:frames:DOM/phphtmllib,HTML:frames:DOM/earthli +;; HTML:Smarty:default,HTML:Smarty:PHP,HTML:Smarty:HandS +;; PDF:default:default,CHM:default:default,XML:DocBook/peardoc2:default +output=HTML:frames:earthli,HTML:frames:default,HTML:frames:l0l33t,HTML:frames:phpdoc.de,HTML:frames:phphtmllib,HTML:frames:DOM/default,HTML:frames:DOM/l0l33t,HTML:frames:DOM/phpdoc.de,HTML:frames:DOM/earthli,HTML:frames:DOM/phphtmllib,HTML:frames:phpedit,HTML:Smarty:default,HTML:Smarty:PHP,HTML:Smarty:HandS,CHM:default:default,PDF:default:default + +;; turn this option on if you want highlighted source code for every file +;; legal values: on/off +sourcecode = on \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/user/demo.ini b/buildscripts/PhpDocumentor/user/demo.ini new file mode 100644 index 00000000..edf0a353 --- /dev/null +++ b/buildscripts/PhpDocumentor/user/demo.ini @@ -0,0 +1,78 @@ +;; phpDocumentor demonstration parse configuration file +;; +;; RUN THIS FILE FROM THE INSTALL DIRECTORY +;; CHANGE HERE: + +;; where should the documentation be written? +;; legal values: a legal path +target = /home/CelloG/output + +;; DONT CHANGE BELOW HERE +;; +;; This file is designed to cut down on repetitive typing on the command-line or web interface +;; You can copy this file to create a number of configuration files that can be used with the +;; command-line switch -c, as in phpdoc -c default.ini or phpdoc -c myini.ini. The web +;; interface will automatically generate a list of .ini files that can be used. +;; +;; ALL .ini files must be in the user subdirectory of phpDocumentor with an extension of .ini +;; +;; Copyright 2002, Greg Beaver +;; +;; WARNING: do not change the + +[Parse Data] +;; title of all the documentation +;; legal values: any string +title = Generated Documentation + +;; parse files that start with a . like .bash_profile +;; legal values: true, false +hidden = false + +;; show elements marked @access private in documentation by setting this to on +;; legal values: on, off +parseprivate = off + +;; parse with javadoc-like description (first sentence is always the short description) +;; legal values: on, off +javadocdesc = off + +target=/dev/null + +;; add any custom @tags separated by commas here +;; legal values: any legal tagname separated by commas. +;customtags = mytag1,mytag2 + +;; what is the main package? +;; legal values: alphanumeric string plus - and _ +defaultpackagename = phpDocumentor + +;; output any parsing information? set to on for cron jobs +;; legal values: on +;quiet = on + +;; limit output to the specified packages, even if others are parsed +;; legal values: package names separated by commas +;packageoutput = package1,package2 + +;; comma-separated list of files to parse +;; legal values: paths separated by commas +;filename = /path/to/file1,/path/to/file2,fileincurrentdirectory +filename = test.php + +;; comma-separated list of directories to parse +;; legal values: directory paths separated by commas +;directory = /path1,/path2,.,..,subdirectory +;directory = /home/jeichorn/cvs/pear +;directory = . + +;; comma-separated list of files, directories or wildcards ? and * (any wildcard) to ignore +;; legal values: any wildcard strings separated by commas +;ignore = /path/to/ignore*,*list.php,myfile.php,subdirectory/ +ignore = templates_c/,*HTML/default/*,spec/ + +;; comma-separated list of Converters to use in outputformat:Convertername:templatedirectory format +;; legal values: HTML:frames:default,HTML:frames:l0l33t,HTML:frames:phpdoc.de,HTML:frames:phphtmllib +;; HTML:frames:phpedit,HTML:frames:DOM/default,HTML:frames:DOM/l0l33t,HTML:frames:DOM/phpdoc.de +;; HTML:Smarty:default,HTML:Smarty:PHP,PDF:default:default,CHM:default:default,XML:DocBook:default +output=HTML:frames:default,HTML:frames:l0l33t,HTML:frames:phpdoc.de,HTML:frames:phphtmllib,HTML:frames:DOM/default,HTML:frames:DOM/l0l33t,HTML:frames:DOM/phpdoc.de,HTML:frames:phpedit,HTML:Smarty:default,HTML:Smarty:HandS,HTML:Smarty:PHP,PDF:default:default,XML:DocBook/peardoc2:default,CHM:default:default \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/user/error.ini b/buildscripts/PhpDocumentor/user/error.ini new file mode 100644 index 00000000..cb8d4ca5 --- /dev/null +++ b/buildscripts/PhpDocumentor/user/error.ini @@ -0,0 +1,82 @@ +;; phpDocumentor parse configuration file +;; +;; This file is designed to cut down on repetitive typing on the command-line or web interface +;; You can copy this file to create a number of configuration files that can be used with the +;; command-line switch -c, as in phpdoc -c default.ini or phpdoc -c myini.ini. The web +;; interface will automatically generate a list of .ini files that can be used. +;; +;; ALL .ini files must be in the user subdirectory of phpDocumentor with an extension of .ini +;; +;; Copyright 2002, Greg Beaver +;; +;; WARNING: do not change the name of any command-line parameters, phpDocumentor will halt + +[Parse Data] +;; title of all the documentation +;; legal values: any string +title = SlateLib Manual + +;; parse files that start with a . like .bash_profile +;; legal values: true, false +hidden = false + +;; show elements marked @access private in documentation by setting this to on +;; legal values: on, off +parseprivate = on + +;; parse with javadoc-like description (first sentence is always the short description) +;; legal values: on, off +javadocdesc = off + +;; add any custom @tags separated by commas here +;; legal values: any legal tagname separated by commas. +;customtags = mytag1,mytag2 + +;; This is only used by the XML:DocBook/peardoc2 converter +defaultcategoryname = Documentation + +;; what is the main package? +;; legal values: alphanumeric string plus - and _ +defaultpackagename = junk + +;; output any parsing information? set to on for cron jobs +;; legal values: on +;quiet = on + +;; parse a PEAR-style repository. Do not turn this on if your project does +;; not have a parent directory named "pear" +;; legal values: on/off +;pear = on + +;; where should the documentation be written? +;; legal values: a legal path +target = /tmp/docs + +;; limit output to the specified packages, even if others are parsed +;; legal values: package names separated by commas +;packageoutput = package1,package2 + +;; comma-separated list of files to parse +;; legal values: paths separated by commas +;filename = /path/to/file1,/path/to/file2,fileincurrentdirectory + +;; comma-separated list of directories to parse +;; legal values: directory paths separated by commas +;directory = /path1,/path2,.,..,subdirectory +;directory = /home/jeichorn/cvs/pear +directory = /home/jeichorn/cvs/slatelib + +;; comma-separated list of files, directories or wildcards ? and * (any wildcard) to ignore +;; legal values: any wildcard strings separated by commas +;ignore = /path/to/ignore*,*list.php,myfile.php,subdirectory/ +ignore = + +;; comma-separated list of Converters to use in outputformat:Convertername:templatedirectory format +;; legal values: HTML:frames:default,HTML:frames:l0l33t,HTML:frames:phpdoc.de,HTML:frames:phphtmllib +;; HTML:frames:DOM/default,HTML:frames:DOM/l0l33t,HTML:frames:DOM/phpdoc.de,HTML:Smarty:default +;; HTML:Smarty:PHP,PDF:default:default,CHM:default:default,XML:DocBook/peardoc2:default +output=HTML:Smarty:default,HTML:Smarty:PHP + +;; turn this option on if you want highlighted source code for every file +;; legal values: on/off +sourcecode = on diff --git a/buildscripts/PhpDocumentor/user/pear-makedocs.ini b/buildscripts/PhpDocumentor/user/pear-makedocs.ini new file mode 100644 index 00000000..750cf48f --- /dev/null +++ b/buildscripts/PhpDocumentor/user/pear-makedocs.ini @@ -0,0 +1,71 @@ +;; phpDocumentor parse configuration file +;; +;; This file is designed to cut down on repetitive typing on the command-line or web interface +;; You can copy this file to create a number of configuration files that can be used with the +;; command-line switch -c, as in phpdoc -c default.ini or phpdoc -c myini.ini. The web +;; interface will automatically generate a list of .ini files that can be used. +;; +;; ALL .ini files must be in the user subdirectory of phpDocumentor with an extension of .ini +;; +;; Copyright 2002, Greg Beaver +;; +;; WARNING: do not change the + +[Parse Data] +;; title of all the documentation +;; legal values: any string +title = phpDocumentor Manual + +;; parse files that start with a . like .bash_profile +;; legal values: true, false +hidden = false + +;; show elements marked @access private in documentation by setting this to on +;; legal values: on, off +parseprivate = off + +;; parse with javadoc-like description (first sentence is always the short description) +;; legal values: on, off +javadocdesc = off + +;; add any custom @tags separated by commas here +;; legal values: any legal tagname separated by commas. +;customtags = mytag1,mytag2 + +;; what is the main package? +;; legal values: alphanumeric string plus - and _ +defaultpackagename = phpDocumentor + +;; output any parsing information? set to on for cron jobs +;; legal values: on +;quiet = on + +;; where should the documentation be written? +;; legal values: a legal path +target = @DOC-DIR@/PhpDocumentor/Documentation/new + +;; limit output to the specified packages, even if others are parsed +;; legal values: package names separated by commas +;packageoutput = package1,package2 + +;; comma-separated list of files to parse +;; legal values: paths separated by commas +;filename = /path/to/file1,/path/to/file2,fileincurrentdirectory +filename = @DOC-DIR@/PhpDocumentor/README,@DOC-DIR@/PhpDocumentor/ChangeLog,@DOC-DIR@/PhpDocumentor/Release-@VER@,@DOC-DIR@/PhpDocumentor/FAQ +;; comma-separated list of directories to parse +;; legal values: directory paths separated by commas +;directory = /path1,/path2,.,..,subdirectory +;directory = /home/jeichorn/cvs/pear +directory = @PEAR-DIR@/PhpDocumentor,@DOC-DIR@/PhpDocumentor/tutorials + +releaseinstallchangelog = Release-@VER@,ChangeLog,README,FAQ + +;; comma-separated list of files, directories or wildcards ? and * (any wildcard) to ignore +;; legal values: any wildcard strings separated by commas +;ignore = /path/to/ignore*,*list.php,myfile.php,subdirectory/ + +;; comma-separated list of Converters to use in outputformat:Convertername:templatedirectory format +;; legal values: HTML:frames:default,HTML:frames:l0l33t,HTML:frames:phpdoc.de,HTML:frames:phphtmllib +;; HTML:frames:DOM/default,HTML:frames:DOM/l0l33t,HTML:frames:DOM/phpdoc.de,HTML:Smarty:default +;; HTML:Smarty:PHP,HTML:Smarty:HandS,PDF:default:default,CHM:default:default,XML:DocBook/peardoc2:default +output=HTML:Smarty:HandS \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/user/prado.ini b/buildscripts/PhpDocumentor/user/prado.ini new file mode 100644 index 00000000..f009f873 --- /dev/null +++ b/buildscripts/PhpDocumentor/user/prado.ini @@ -0,0 +1,79 @@ +;; phpDocumentor demonstration parse configuration file +;; +;; RUN THIS FILE FROM THE INSTALL DIRECTORY +;; CHANGE HERE: + +;; where should the documentation be written? +;; legal values: a legal path +target = d:/wwwroot/prado3-doc + +;; DONT CHANGE BELOW HERE +;; +;; This file is designed to cut down on repetitive typing on the command-line or web interface +;; You can copy this file to create a number of configuration files that can be used with the +;; command-line switch -c, as in phpdoc -c default.ini or phpdoc -c myini.ini. The web +;; interface will automatically generate a list of .ini files that can be used. +;; +;; ALL .ini files must be in the user subdirectory of phpDocumentor with an extension of .ini +;; +;; Copyright 2002, Greg Beaver +;; +;; WARNING: do not change the + +[Parse Data] +;; title of all the documentation +;; legal values: any string +title = PRADO 3.0.1 API Manual + +;; parse files that start with a . like .bash_profile +;; legal values: true, false +hidden = false + +;; show elements marked @access private in documentation by setting this to on +;; legal values: on, off +parseprivate = off + +;; parse with javadoc-like description (first sentence is always the short description) +;; legal values: on, off +javadocdesc = off + +target=d:/wwwroot/prado3-doc/manual + +;; add any custom @tags separated by commas here +;; legal values: any legal tagname separated by commas. +;customtags = mytag1,mytag2 + +;; what is the main package? +;; legal values: alphanumeric string plus - and _ +defaultpackagename = default + +;; output any parsing information? set to on for cron jobs +;; legal values: on +;quiet = on + +;; limit output to the specified packages, even if others are parsed +;; legal values: package names separated by commas +;packageoutput = package1,package2 + +;; comma-separated list of files to parse +;; legal values: paths separated by commas +;filename = /path/to/file1,/path/to/file2,fileincurrentdirectory +;filename = + +;; comma-separated list of directories to parse +;; legal values: directory paths separated by commas +directory = D:/wwwroot/prado3-doc/prado-3.0.1/framework +;directory = /home/jeichorn/cvs/pear +;directory = . + +;; comma-separated list of files, directories or wildcards ? and * (any wildcard) to ignore +;; legal values: any wildcard strings separated by commas +;ignore = /path/to/ignore*,*list.php,myfile.php,subdirectory/ +ignore = templates_c/,*HTML/default/*,spec/,*pradolite.php,*3rdParty/*,*Javascripts/* + +;; comma-separated list of Converters to use in outputformat:Convertername:templatedirectory format +;; legal values: HTML:frames:default,HTML:frames:l0l33t,HTML:frames:phpdoc.de,HTML:frames:phphtmllib +;; HTML:frames:phpedit,HTML:frames:DOM/default,HTML:frames:DOM/l0l33t,HTML:frames:DOM/phpdoc.de +;; HTML:Smarty:default,HTML:Smarty:PHP,PDF:default:default,CHM:default:default,XML:DocBook:default +;;output=HTML:frames:default,CHM:default:default +output=HTML:Smarty:PradoSoft \ No newline at end of file diff --git a/buildscripts/PhpDocumentor/user/testdocbook.ini b/buildscripts/PhpDocumentor/user/testdocbook.ini new file mode 100644 index 00000000..8de48fc0 --- /dev/null +++ b/buildscripts/PhpDocumentor/user/testdocbook.ini @@ -0,0 +1,74 @@ +;; phpDocumentor parse configuration file +;; +;; This file is designed to cut down on repetitive typing on the command-line or web interface +;; You can copy this file to create a number of configuration files that can be used with the +;; command-line switch -c, as in phpdoc -c default.ini or phpdoc -c myini.ini. The web +;; interface will automatically generate a list of .ini files that can be used. +;; +;; ALL .ini files must be in the user subdirectory of phpDocumentor with an extension of .ini +;; +;; Copyright 2002, Greg Beaver +;; +;; WARNING: do not change the + +[Parse Data] +;; title of all the documentation +;; legal values: any string +title = Generated Documentation + +;; parse files that start with a . like .bash_profile +;; legal values: true, false +hidden = false + +;; show elements marked @access private in documentation by setting this to on +;; legal values: on, off +parseprivate = off + +pear=on + +;; parse with javadoc-like description (first sentence is always the short description) +;; legal values: on, off +javadocdesc = off + +;; add any custom @tags separated by commas here +;; legal values: any legal tagname separated by commas. +;customtags = mytag1,mytag2 + +;; what is the main package? +;; legal values: alphanumeric string plus - and _ +defaultpackagename = PEAR_PackageFileManager + +defaultcategoryname = pear + +;; output any parsing information? set to on for cron jobs +;; legal values: on +;quiet = on + +;; where should the documentation be written? +;; legal values: a legal path +target = /home/cellog/peardoc/en/package + +;; limit output to the specified packages, even if others are parsed +;; legal values: package names separated by commas +;packageoutput = package1,package2 + +;; comma-separated list of files to parse +;; legal values: paths separated by commas +;filename = /path/to/file1,/path/to/file2,fileincurrentdirectory + +;; comma-separated list of directories to parse +;; legal values: directory paths separated by commas +;directory = /path1,/path2,.,..,subdirectory +directory = /home/cellog/pear/PEAR_PackageFileManager +;directory = /home/CelloG/phpdoc + +;; comma-separated list of files, directories or wildcards ? and * (any wildcard) to ignore +;; legal values: any wildcard strings separated by commas +;ignore = /path/to/ignore*,*list.php,myfile.php,subdirectory/ +ignore = examples/ + +;; comma-separated list of Converters to use in outputformat:Convertername:templatedirectory format +;; legal values: HTML:frames:default,HTML:frames:l0l33t,HTML:frames:phpdoc.de,HTML:frames:phphtmllib +;; HTML:frames:DOM/default,HTML:frames:DOM/l0l33t,HTML:frames:DOM/phpdoc.de,HTML:Smarty:default +;; HTML:Smarty:PHP,PDF:default:default,CHM:default:default,XML:DocBook:default +output=XML:DocBook/peardoc2:default diff --git a/buildscripts/index/api_index.php b/buildscripts/index/api_index.php index ac2e37a7..c85fa267 100644 --- a/buildscripts/index/api_index.php +++ b/buildscripts/index/api_index.php @@ -25,6 +25,7 @@ class api_index $count = 0; foreach($files as $file) { + echo " processing $file...\n"; $content = $this->get_details($file, $this->_api); $doc = new Zend_Search_Lucene_Document(); @@ -86,8 +87,8 @@ class api_index if(is_file($filepath) && $entry[0] !== '_') $files[] = realpath($filepath); } - return $files; $d->close(); + return $files; } function get_doc_content($file) diff --git a/buildscripts/index/search.php b/buildscripts/index/search.php new file mode 100644 index 00000000..a34363f4 --- /dev/null +++ b/buildscripts/index/search.php @@ -0,0 +1,36 @@ +find(strtolower($keyword)); + $content=''; + foreach($results as $entry) + $content.="
                                              • link}\">{$entry->title}
                                              • \n"; + if($content!=='') + { + $count=count($results); + $content="

                                                Total $count pages matching keyword ".htmlentities($keyword).".\n

                                                  \n$content
                                                \n"; + } + else + $content="

                                                No page matches ".htmlentities($keyword).".

                                                "; +} +else + $content="

                                                Please specify a keyword to search for.

                                                "; + +$page=file_get_contents(dirname(__FILE__).'/index.html'); +$page=preg_replace('/.*/ms',$content,$page); +if($keyword!=='') + $page=preg_replace('/ \ No newline at end of file diff --git a/buildscripts/phing/CREDITS b/buildscripts/phing/CREDITS new file mode 100644 index 00000000..0aff0706 --- /dev/null +++ b/buildscripts/phing/CREDITS @@ -0,0 +1,45 @@ + _________________________ + P H I N G + + New PHP5 PHING/2 Development + ---------------------------- + + Hans Lellelid + David Giffin + Michiel Rook + Sebastian Bergmann + + If you've done work on phing and you are not listed here, please feel free + to add yourself. + + Original PHING/1 Development + ----------------------------- + + Andreas Aderhold + Alex Black + Albert Lash + Charlie Killian + Manuel Holtgrewe + Andrzej Nowodworski + Jason Hines + Jesse Estevez + Andris Spruds + Ronald TAO + Yannick Lecaillez + Hans Lellelid + + Other libraries/contributions + ------------------------------ + + Apache ANT Project + License: Apache 1.1 + Phing is a port of the Apache ANT project. + http://ant.apache.org/ + + TAR Manager Class + License: LGPL + The Tar archive abstraction class + (c) Josh Barger + http://phpclasses.upperdesign.com/browse.html/package/529.html + + --$Id: CREDITS,v 1.6 2005/02/03 13:41:52 mrook Exp $ diff --git a/buildscripts/phing/LICENSE b/buildscripts/phing/LICENSE new file mode 100644 index 00000000..9139d608 --- /dev/null +++ b/buildscripts/phing/LICENSE @@ -0,0 +1,1042 @@ + _________________________ + + P H I N G + + + + + + Please, be sure to read the license header on any one of the phing core + + files. It explains the licensing scheme. + + + + Some files in phing are Perl Artistic, Apache, BSD, or just free. See + + "CREDITS" for a list. + + + + We've included a copy of the LGPL for convenience. + + + + + + LGPL LICENSE + + ------------ + + + + GNU LESSER GENERAL PUBLIC LICENSE + + Version 2.1, February 1999 + + + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Everyone is permitted to copy and distribute verbatim copies + + of this license document, but changing it is not allowed. + + + + [This is the first released version of the Lesser GPL. It also counts + + as the successor of the GNU Library Public License, version 2, hence + + the version number 2.1.] + + + + Preamble + + + + The licenses for most software are designed to take away your + + freedom to share and change it. By contrast, the GNU General Public + + Licenses are intended to guarantee your freedom to share and change + + free software--to make sure the software is free for all its users. + + + + This license, the Lesser General Public License, applies to some + + specially designated software packages--typically libraries--of the + + Free Software Foundation and other authors who decide to use it. You + + can use it too, but we suggest you first think carefully about whether + + this license or the ordinary General Public License is the better + + strategy to use in any particular case, based on the explanations below. + + + + When we speak of free software, we are referring to freedom of use, + + not price. Our General Public Licenses are designed to make sure that + + you have the freedom to distribute copies of free software (and charge + + for this service if you wish); that you receive source code or can get + + it if you want it; that you can change the software and use pieces of + + it in new free programs; and that you are informed that you can do + + these things. + + + + To protect your rights, we need to make restrictions that forbid + + distributors to deny you these rights or to ask you to surrender these + + rights. These restrictions translate to certain responsibilities for + + you if you distribute copies of the library or if you modify it. + + + + For example, if you distribute copies of the library, whether gratis + + or for a fee, you must give the recipients all the rights that we gave + + you. You must make sure that they, too, receive or can get the source + + code. If you link other code with the library, you must provide + + complete object files to the recipients, so that they can relink them + + with the library after making changes to the library and recompiling + + it. And you must show them these terms so they know their rights. + + + + We protect your rights with a two-step method: (1) we copyright the + + library, and (2) we offer you this license, which gives you legal + + permission to copy, distribute and/or modify the library. + + + + To protect each distributor, we want to make it very clear that + + there is no warranty for the free library. Also, if the library is + + modified by someone else and passed on, the recipients should know + + that what they have is not the original version, so that the original + + author's reputation will not be affected by problems that might be + + introduced by others. + + + + Finally, software patents pose a constant threat to the existence of + + any free program. We wish to make sure that a company cannot + + effectively restrict the users of a free program by obtaining a + + restrictive license from a patent holder. Therefore, we insist that + + any patent license obtained for a version of the library must be + + consistent with the full freedom of use specified in this license. + + + + Most GNU software, including some libraries, is covered by the + + ordinary GNU General Public License. This license, the GNU Lesser + + General Public License, applies to certain designated libraries, and + + is quite different from the ordinary General Public License. We use + + this license for certain libraries in order to permit linking those + + libraries into non-free programs. + + + + When a program is linked with a library, whether statically or using + + a shared library, the combination of the two is legally speaking a + + combined work, a derivative of the original library. The ordinary + + General Public License therefore permits such linking only if the + + entire combination fits its criteria of freedom. The Lesser General + + Public License permits more lax criteria for linking other code with + + the library. + + + + We call this license the "Lesser" General Public License because it + + does Less to protect the user's freedom than the ordinary General + + Public License. It also provides other free software developers Less + + of an advantage over competing non-free programs. These disadvantages + + are the reason we use the ordinary General Public License for many + + libraries. However, the Lesser license provides advantages in certain + + special circumstances. + + + + For example, on rare occasions, there may be a special need to + + encourage the widest possible use of a certain library, so that it + + becomes a de-facto standard. To achieve this, non-free programs must be + + allowed to use the library. A more frequent case is that a free + + library does the same job as widely used non-free libraries. In this + + case, there is little to gain by limiting the free library to free + + software only, so we use the Lesser General Public License. + + + + In other cases, permission to use a particular library in non-free + + programs enables a greater number of people to use a large body of + + free software. For example, permission to use the GNU C Library in + + non-free programs enables many more people to use the whole GNU + + operating system, as well as its variant, the GNU/Linux operating + + system. + + + + Although the Lesser General Public License is Less protective of the + + users' freedom, it does ensure that the user of a program that is + + linked with the Library has the freedom and the wherewithal to run + + that program using a modified version of the Library. + + + + The precise terms and conditions for copying, distribution and + + modification follow. Pay close attention to the difference between a + + "work based on the library" and a "work that uses the library". The + + former contains code derived from the library, whereas the latter must + + be combined with the library in order to run. + + + + GNU LESSER GENERAL PUBLIC LICENSE + + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + + + 0. This License Agreement applies to any software library or other + + program which contains a notice placed by the copyright holder or + + other authorized party saying it may be distributed under the terms of + + this Lesser General Public License (also called "this License"). + + Each licensee is addressed as "you". + + + + A "library" means a collection of software functions and/or data + + prepared so as to be conveniently linked with application programs + + (which use some of those functions and data) to form executables. + + + + The "Library", below, refers to any such software library or work + + which has been distributed under these terms. A "work based on the + + Library" means either the Library or any derivative work under + + copyright law: that is to say, a work containing the Library or a + + portion of it, either verbatim or with modifications and/or translated + + straightforwardly into another language. (Hereinafter, translation is + + included without limitation in the term "modification".) + + + + "Source code" for a work means the preferred form of the work for + + making modifications to it. For a library, complete source code means + + all the source code for all modules it contains, plus any associated + + interface definition files, plus the scripts used to control compilation + + and installation of the library. + + + + Activities other than copying, distribution and modification are not + + covered by this License; they are outside its scope. The act of + + running a program using the Library is not restricted, and output from + + such a program is covered only if its contents constitute a work based + + on the Library (independent of the use of the Library in a tool for + + writing it). Whether that is true depends on what the Library does + + and what the program that uses the Library does. + + + + 1. You may copy and distribute verbatim copies of the Library's + + complete source code as you receive it, in any medium, provided that + + you conspicuously and appropriately publish on each copy an + + appropriate copyright notice and disclaimer of warranty; keep intact + + all the notices that refer to this License and to the absence of any + + warranty; and distribute a copy of this License along with the + + Library. + + + + You may charge a fee for the physical act of transferring a copy, + + and you may at your option offer warranty protection in exchange for a + + fee. + + + + 2. You may modify your copy or copies of the Library or any portion + + of it, thus forming a work based on the Library, and copy and + + distribute such modifications or work under the terms of Section 1 + + above, provided that you also meet all of these conditions: + + + + a) The modified work must itself be a software library. + + + + b) You must cause the files modified to carry prominent notices + + stating that you changed the files and the date of any change. + + + + c) You must cause the whole of the work to be licensed at no + + charge to all third parties under the terms of this License. + + + + d) If a facility in the modified Library refers to a function or a + + table of data to be supplied by an application program that uses + + the facility, other than as an argument passed when the facility + + is invoked, then you must make a good faith effort to ensure that, + + in the event an application does not supply such function or + + table, the facility still operates, and performs whatever part of + + its purpose remains meaningful. + + + + (For example, a function in a library to compute square roots has + + a purpose that is entirely well-defined independent of the + + application. Therefore, Subsection 2d requires that any + + application-supplied function or table used by this function must + + be optional: if the application does not supply it, the square + + root function must still compute square roots.) + + + + These requirements apply to the modified work as a whole. If + + identifiable sections of that work are not derived from the Library, + + and can be reasonably considered independent and separate works in + + themselves, then this License, and its terms, do not apply to those + + sections when you distribute them as separate works. But when you + + distribute the same sections as part of a whole which is a work based + + on the Library, the distribution of the whole must be on the terms of + + this License, whose permissions for other licensees extend to the + + entire whole, and thus to each and every part regardless of who wrote + + it. + + + + Thus, it is not the intent of this section to claim rights or contest + + your rights to work written entirely by you; rather, the intent is to + + exercise the right to control the distribution of derivative or + + collective works based on the Library. + + + + In addition, mere aggregation of another work not based on the Library + + with the Library (or with a work based on the Library) on a volume of + + a storage or distribution medium does not bring the other work under + + the scope of this License. + + + + 3. You may opt to apply the terms of the ordinary GNU General Public + + License instead of this License to a given copy of the Library. To do + + this, you must alter all the notices that refer to this License, so + + that they refer to the ordinary GNU General Public License, version 2, + + instead of to this License. (If a newer version than version 2 of the + + ordinary GNU General Public License has appeared, then you can specify + + that version instead if you wish.) Do not make any other change in + + these notices. + + + + Once this change is made in a given copy, it is irreversible for + + that copy, so the ordinary GNU General Public License applies to all + + subsequent copies and derivative works made from that copy. + + + + This option is useful when you wish to copy part of the code of + + the Library into a program that is not a library. + + + + 4. You may copy and distribute the Library (or a portion or + + derivative of it, under Section 2) in object code or executable form + + under the terms of Sections 1 and 2 above provided that you accompany + + it with the complete corresponding machine-readable source code, which + + must be distributed under the terms of Sections 1 and 2 above on a + + medium customarily used for software interchange. + + + + If distribution of object code is made by offering access to copy + + from a designated place, then offering equivalent access to copy the + + source code from the same place satisfies the requirement to + + distribute the source code, even though third parties are not + + compelled to copy the source along with the object code. + + + + 5. A program that contains no derivative of any portion of the + + Library, but is designed to work with the Library by being compiled or + + linked with it, is called a "work that uses the Library". Such a + + work, in isolation, is not a derivative work of the Library, and + + therefore falls outside the scope of this License. + + + + However, linking a "work that uses the Library" with the Library + + creates an executable that is a derivative of the Library (because it + + contains portions of the Library), rather than a "work that uses the + + library". The executable is therefore covered by this License. + + Section 6 states terms for distribution of such executables. + + + + When a "work that uses the Library" uses material from a header file + + that is part of the Library, the object code for the work may be a + + derivative work of the Library even though the source code is not. + + Whether this is true is especially significant if the work can be + + linked without the Library, or if the work is itself a library. The + + threshold for this to be true is not precisely defined by law. + + + + If such an object file uses only numerical parameters, data + + structure layouts and accessors, and small macros and small inline + + functions (ten lines or less in length), then the use of the object + + file is unrestricted, regardless of whether it is legally a derivative + + work. (Executables containing this object code plus portions of the + + Library will still fall under Section 6.) + + + + Otherwise, if the work is a derivative of the Library, you may + + distribute the object code for the work under the terms of Section 6. + + Any executables containing that work also fall under Section 6, + + whether or not they are linked directly with the Library itself. + + + + 6. As an exception to the Sections above, you may also combine or + + link a "work that uses the Library" with the Library to produce a + + work containing portions of the Library, and distribute that work + + under terms of your choice, provided that the terms permit + + modification of the work for the customer's own use and reverse + + engineering for debugging such modifications. + + + + You must give prominent notice with each copy of the work that the + + Library is used in it and that the Library and its use are covered by + + this License. You must supply a copy of this License. If the work + + during execution displays copyright notices, you must include the + + copyright notice for the Library among them, as well as a reference + + directing the user to the copy of this License. Also, you must do one + + of these things: + + + + a) Accompany the work with the complete corresponding + + machine-readable source code for the Library including whatever + + changes were used in the work (which must be distributed under + + Sections 1 and 2 above); and, if the work is an executable linked + + with the Library, with the complete machine-readable "work that + + uses the Library", as object code and/or source code, so that the + + user can modify the Library and then relink to produce a modified + + executable containing the modified Library. (It is understood + + that the user who changes the contents of definitions files in the + + Library will not necessarily be able to recompile the application + + to use the modified definitions.) + + + + b) Use a suitable shared library mechanism for linking with the + + Library. A suitable mechanism is one that (1) uses at run time a + + copy of the library already present on the user's computer system, + + rather than copying library functions into the executable, and (2) + + will operate properly with a modified version of the library, if + + the user installs one, as long as the modified version is + + interface-compatible with the version that the work was made with. + + + + c) Accompany the work with a written offer, valid for at + + least three years, to give the same user the materials + + specified in Subsection 6a, above, for a charge no more + + than the cost of performing this distribution. + + + + d) If distribution of the work is made by offering access to copy + + from a designated place, offer equivalent access to copy the above + + specified materials from the same place. + + + + e) Verify that the user has already received a copy of these + + materials or that you have already sent this user a copy. + + + + For an executable, the required form of the "work that uses the + + Library" must include any data and utility programs needed for + + reproducing the executable from it. However, as a special exception, + + the materials to be distributed need not include anything that is + + normally distributed (in either source or binary form) with the major + + components (compiler, kernel, and so on) of the operating system on + + which the executable runs, unless that component itself accompanies + + the executable. + + + + It may happen that this requirement contradicts the license + + restrictions of other proprietary libraries that do not normally + + accompany the operating system. Such a contradiction means you cannot + + use both them and the Library together in an executable that you + + distribute. + + + + 7. You may place library facilities that are a work based on the + + Library side-by-side in a single library together with other library + + facilities not covered by this License, and distribute such a combined + + library, provided that the separate distribution of the work based on + + the Library and of the other library facilities is otherwise + + permitted, and provided that you do these two things: + + + + a) Accompany the combined library with a copy of the same work + + based on the Library, uncombined with any other library + + facilities. This must be distributed under the terms of the + + Sections above. + + + + b) Give prominent notice with the combined library of the fact + + that part of it is a work based on the Library, and explaining + + where to find the accompanying uncombined form of the same work. + + + + 8. You may not copy, modify, sublicense, link with, or distribute + + the Library except as expressly provided under this License. Any + + attempt otherwise to copy, modify, sublicense, link with, or + + distribute the Library is void, and will automatically terminate your + + rights under this License. However, parties who have received copies, + + or rights, from you under this License will not have their licenses + + terminated so long as such parties remain in full compliance. + + + + 9. You are not required to accept this License, since you have not + + signed it. However, nothing else grants you permission to modify or + + distribute the Library or its derivative works. These actions are + + prohibited by law if you do not accept this License. Therefore, by + + modifying or distributing the Library (or any work based on the + + Library), you indicate your acceptance of this License to do so, and + + all its terms and conditions for copying, distributing or modifying + + the Library or works based on it. + + + + 10. Each time you redistribute the Library (or any work based on the + + Library), the recipient automatically receives a license from the + + original licensor to copy, distribute, link with or modify the Library + + subject to these terms and conditions. You may not impose any further + + restrictions on the recipients' exercise of the rights granted herein. + + You are not responsible for enforcing compliance by third parties with + + this License. + + + + 11. If, as a consequence of a court judgment or allegation of patent + + infringement or for any other reason (not limited to patent issues), + + conditions are imposed on you (whether by court order, agreement or + + otherwise) that contradict the conditions of this License, they do not + + excuse you from the conditions of this License. If you cannot + + distribute so as to satisfy simultaneously your obligations under this + + License and any other pertinent obligations, then as a consequence you + + may not distribute the Library at all. For example, if a patent + + license would not permit royalty-free redistribution of the Library by + + all those who receive copies directly or indirectly through you, then + + the only way you could satisfy both it and this License would be to + + refrain entirely from distribution of the Library. + + + + If any portion of this section is held invalid or unenforceable under any + + particular circumstance, the balance of the section is intended to apply, + + and the section as a whole is intended to apply in other circumstances. + + + + It is not the purpose of this section to induce you to infringe any + + patents or other property right claims or to contest validity of any + + such claims; this section has the sole purpose of protecting the + + integrity of the free software distribution system which is + + implemented by public license practices. Many people have made + + generous contributions to the wide range of software distributed + + through that system in reliance on consistent application of that + + system; it is up to the author/donor to decide if he or she is willing + + to distribute software through any other system and a licensee cannot + + impose that choice. + + + + This section is intended to make thoroughly clear what is believed to + + be a consequence of the rest of this License. + + + + 12. If the distribution and/or use of the Library is restricted in + + certain countries either by patents or by copyrighted interfaces, the + + original copyright holder who places the Library under this License may + + add an explicit geographical distribution limitation excluding those + + countries, so that distribution is permitted only in or among countries + + not thus excluded. In such case, this License incorporates the + + limitation as if written in the body of this License. + + + + 13. The Free Software Foundation may publish revised and/or new + + versions of the Lesser General Public License from time to time. + + Such new versions will be similar in spirit to the present version, + + but may differ in detail to address new problems or concerns. + + + + Each version is given a distinguishing version number. If the Library + + specifies a version number of this License which applies to it and + + "any later version", you have the option of following the terms and + + conditions either of that version or of any later version published by + + the Free Software Foundation. If the Library does not specify a + + license version number, you may choose any version ever published by + + the Free Software Foundation. + + + + 14. If you wish to incorporate parts of the Library into other free + + programs whose distribution conditions are incompatible with these, + + write to the author to ask for permission. For software which is + + copyrighted by the Free Software Foundation, write to the Free + + Software Foundation; we sometimes make exceptions for this. Our + + decision will be guided by the two goals of preserving the free status + + of all derivatives of our free software and of promoting the sharing + + and reuse of software generally. + + + + NO WARRANTY + + + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO + + WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. + + EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR + + OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY + + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE + + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + + PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE + + LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME + + THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN + + WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY + + AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU + + FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR + + CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE + + LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING + + RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A + + FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF + + SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + + DAMAGES. + + + + END OF TERMS AND CONDITIONS + + + + How to Apply These Terms to Your New Libraries + + + + If you develop a new library, and you want it to be of the greatest + + possible use to the public, we recommend making it free software that + + everyone can redistribute and change. You can do so by permitting + + redistribution under these terms (or, alternatively, under the terms of the + + ordinary General Public License). + + + + To apply these terms, attach the following notices to the library. It is + + safest to attach them to the start of each source file to most effectively + + convey the exclusion of warranty; and each file should have at least the + + "copyright" line and a pointer to where the full notice is found. + + + + + + Copyright (C) + + + + This library is free software; you can redistribute it and/or + + modify it under the terms of the GNU Lesser General Public + + License as published by the Free Software Foundation; either + + version 2.1 of the License, or (at your option) any later version. + + + + This library is distributed in the hope that it will be useful, + + but WITHOUT ANY WARRANTY; without even the implied warranty of + + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + + Lesser General Public License for more details. + + + + You should have received a copy of the GNU Lesser General Public + + License along with this library; if not, write to the Free Software + + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + + Also add information on how to contact you by electronic and paper mail. + + + + You should also get your employer (if you work as a programmer) or your + + school, if any, to sign a "copyright disclaimer" for the library, if + + necessary. Here is a sample; alter the names: + + + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + + + , 1 April 1990 + + Ty Coon, President of Vice + + + + That's all there is to it! + + + + --$Id: LICENSE,v 1.3 2003/11/06 18:18:06 hlellelid Exp $ + + + diff --git a/buildscripts/phing/README b/buildscripts/phing/README new file mode 100644 index 00000000..c2b64302 --- /dev/null +++ b/buildscripts/phing/README @@ -0,0 +1,78 @@ + _________________________ + P H I N G + + + + What is it? + ----------- + + Phing is a PHP based build tool. In theory it is kind of like "make" + without makes drawbacks and with the full portability and performance + of PHP. (PH)pmake (I)s (N)ot (G)numake + + Why? + ---- + + Why another build tool when there is already make, gnumake, nmake, jam, ant, + and others? Because all those tools have limitations that the binarycloud + development team could not live with when developing software across + different platforms. Make-like tools are inherently shell-based: they + evaluate a set of dependencies, then execute commands not unlike what you + would issue on a shell. + + This means that you can easily extend these tools by using or writing any + program for the OS that you are working on; however, this also means that + you limit yourself to the OS, or at least the OS type, such as Unix, that + you are working on. + + Makefiles are inherently evil as well. Anybody who has worked on them for + any time has run into the dreaded tab problem. "Is my command not executing + because I have a space in front of my tab?!!". Tools like Jam took care of + this to a great degree, but still have yet another format to use and + remember. Of course there is the Java based build tool ant, that is very + good approach to what now Phing is. But still based on Java you have to have + at least a running JRE installation on your plattfrom. + Great for Java projects but we thought this is very consistent way to build + a PHP based project. Additionally ant does not support a autoconf tool that + writes out proper buildfiles based on some simple rules prior defined in a + XML Configuration file. + + Phing is different. Instead of a model where it is extended with shell-based + commands, Phing is extended using PHP classes. Instead of writing shell + commands, the configuration files are XML-based, calling a target tree where + various tasks get executed. Each task is run by an object that implements + a particular Task action. + + Of course, this removes some of the expressive power that is inherent in + being able to construct a shell command such as + % `find . -name foo -exec rm {}` + but it gives you the ability to be cross-platform - to work anywhere and + everywhere. And if you really need to execute a shell command, Phing has an + task that allows different commands to be executed based on the operating + system it is executing on. + + The Latest Version + ------------------ + + Details of the latest version can be found on the Phing homepage + . + + Documentation + ------------- + + Documentation is available in XHTML format in the docs/ directory. In particular, + open the docs/phing_guide/book/index.html in a frames-compatible browser to see the + phing user guide. + + For installing see INSTALL. files in the Phing root. + + Licensing + --------- + + This software is licensed under the terms you may find in the file + named "LICENSE" in this directory. + + Thanks for using PHING. + + + --$Id: README,v 1.4 2004/03/20 04:14:35 hlellelid Exp $ diff --git a/buildscripts/phing/bin/pear-phing b/buildscripts/phing/bin/pear-phing new file mode 100644 index 00000000..bf568c17 --- /dev/null +++ b/buildscripts/phing/bin/pear-phing @@ -0,0 +1,22 @@ +#!/bin/sh + +# ------------------------------------------------------------------------ +# The phing build script for Unix based systems +# $Id: pear-phing,v 1.3 2003/12/23 19:45:14 hlellelid Exp $ +# ------------------------------------------------------------------------ + +# Change this to reflect your environment if the default value doesn't work +PHP_COMMAND="@PHP-BIN@" +export PHP_COMMAND + +# ------------------------------------------------------------------------- +# Do not change anything below this line unless you know what you're doing. +# ------------------------------------------------------------------------- + +if (test -z "$PHP_COMMAND") ; then + echo "WARNING: PHP_COMMAND environment not set. (Assuming php on PATH)" + PHP_COMMAND=php + export PHP_COMMAND +fi + +$PHP_COMMAND -d html_errors=off -qC @PEAR-DIR@/phing.php -logger phing.listener.AnsiColorLogger $* diff --git a/buildscripts/phing/bin/pear-phing.bat b/buildscripts/phing/bin/pear-phing.bat new file mode 100644 index 00000000..fba90772 --- /dev/null +++ b/buildscripts/phing/bin/pear-phing.bat @@ -0,0 +1,44 @@ +@ECHO OFF + +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: The phing build script for Windows based systems +:: $Id: pear-phing.bat,v 1.4 2005/12/22 13:12:33 hlellelid Exp $ +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +::---------------------------------------------------------------------------------- +:: Please set following to PHP's CLI +:: NOTE: In PHP 4.2.x the PHP-CLI used to be named php-cli.exe. +:: PHP 4.3.x names it php.exe but stores it in a subdir called /cli/php.exe +:: E.g. for PHP 4.2 C:\phpdev\php-4.2-Win32\php-cli.exe +:: for PHP 4.3 C:\phpdev\php-4.3-Win32\cli\php.exe + + SET phpCli=@PHP-BIN@ + +::--------------------------------------------------------------------------------- +::--------------------------------------------------------------------------------- +:: Do not modify below this line!! (Unless you know what your doing :) +::--------------------------------------------------------------------------------- +::--------------------------------------------------------------------------------- + +:: Check existence of php.exe +IF EXIST "%phpCli%" ( + SET doNothing= +) ELSE GOTO :NoPhpCli + +"%phpCli%" -d html_errors=off -qC "@PEAR-DIR@\phing.php" %* +GOTO :EOF + +:: +:: php.exe not found error +GOTO :PAUSE_END +:NoPhpCli +ECHO ** ERROR ***************************************************************** +ECHO * Sorry, can't find the php.exe file. +ECHO * You must edit this file to point to your php.exe (CLI version!) +ECHO * [Currently set to %phpCli%] +ECHO ************************************************************************** + +GOTO :PAUSE_END + +:PAUSE_END +PAUSE \ No newline at end of file diff --git a/buildscripts/phing/bin/phing b/buildscripts/phing/bin/phing new file mode 100644 index 00000000..e24c6cfb --- /dev/null +++ b/buildscripts/phing/bin/phing @@ -0,0 +1,75 @@ +#!/bin/sh +# Shell wrapper for Phing +# $Id: phing,v 1.2 2006/01/23 21:51:16 mrook Exp $ +# +# This script will do the following: +# - check for PHP_COMMAND env, if found, use it. +# - if not found assume php is on the path +# - check for PHING_HOME evn, if found use it +# - if not look for it +# - check for PHP_CLASSPATH, if found use it +# - if not found set it using PHING_HOME/classes + +if [ -z "$PHING_HOME" ] ; then + + # echo "WARNING: PHING_HOME environment not set. Attempting to guess." + + # try to find PHING + if [ -d /opt/phing ] ; then + PHING_HOME=/opt/phing + fi + + if [ -d "${HOME}/opt/phing" ] ; then + PHING_HOME="${HOME}/opt/phing" + fi + + if [ -d "/usr/local/phing" ] ; then + PHING_HOME="/usr/local/phing" + fi + + if [ -d "${HOME}/usr/phing" ] ; then + PHING_HOME="${HOME}/usr/phing" + fi + + ## resolve links - $0 may be a link to phing's home + PRG="$0" + progname=`basename "$0"` + saveddir=`pwd` + + # need this for relative symlinks + dirname_prg=`dirname "$PRG"` + cd "$dirname_prg" + + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi + done + + PHING_HOME=`dirname "$PRG"`/.. + + cd "$saveddir" + + # make it fully qualified + PHING_HOME=`cd "$PHING_HOME" && pwd` + + # make it available in PHP via getenv("PHING_HOME") + export PHING_HOME +fi + +if (test -z "$PHP_COMMAND") ; then + # echo "WARNING: PHP_COMMAND environment not set. (Assuming php on PATH)" + PHP_COMMAND=php + export PHP_COMMAND +fi + +if (test -z "$PHP_CLASSPATH") ; then + PHP_CLASSPATH=$PHING_HOME/classes + export PHP_CLASSPATH +fi + +$PHP_COMMAND -d html_errors=off -qC $PHING_HOME/bin/phing.php -logger phing.listener.AnsiColorLogger $@ diff --git a/buildscripts/phing/bin/phing.bat b/buildscripts/phing/bin/phing.bat new file mode 100644 index 00000000..c57c30dd --- /dev/null +++ b/buildscripts/phing/bin/phing.bat @@ -0,0 +1,58 @@ +@echo off + +rem ********************************************************************* +rem ** the phing build script for Windows based systems +rem ** $Id: phing.bat,v 1.5 2003/11/06 14:56:13 hlellelid Exp $ +rem ********************************************************************* + +rem This script will do the following: +rem - check for PHP_COMMAND env, if found, use it. +rem - if not found detect php, if found use it, otherwise err and terminate +rem - check for PHING_HOME evn, if found use it +rem - if not found error and leave +rem - check for PHP_CLASSPATH, if found use it +rem - if not found set it using PHING_HOME/classes + +if "%OS%"=="Windows_NT" @setlocal + +rem %~dp0 is expanded pathname of the current script under NT +set DEFAULT_PHING_HOME=%~dp0.. + +goto init +goto cleanup + +:init + +if "%PHING_HOME%" == "" set PHING_HOME=%DEFAULT_PHING_HOME% +set DEFAULT_PHING_HOME= + +if "%PHP_COMMAND%" == "" goto no_phpcommand +if "%PHP_CLASSPATH%" == "" goto set_classpath + +goto run +goto cleanup + +:run +%PHP_COMMAND% -d html_errors=off -qC %PHING_HOME%\bin\phing.php %1 %2 %3 %4 %5 %6 %7 %8 %9 +goto cleanup + +:no_phpcommand +REM echo ------------------------------------------------------------------------ +REM echo WARNING: Set environment var PHP_COMMAND to the location of your php.exe +REM echo executable (e.g. C:\PHP\php.exe). (Assuming php.exe on Path) +REM echo ------------------------------------------------------------------------ +set PHP_COMMAND=php.exe +goto init + +:err_home +echo ERROR: Environment var PHING_HOME not set. Please point this +echo variable to your local phing installation! +goto cleanup + +:set_classpath +set PHP_CLASSPATH="%PHING_HOME%\classes" +goto init + +:cleanup +if "%OS%"=="Windows_NT" @endlocal +REM pause diff --git a/buildscripts/phing/bin/phing.php b/buildscripts/phing/bin/phing.php new file mode 100644 index 00000000..880adf41 --- /dev/null +++ b/buildscripts/phing/bin/phing.php @@ -0,0 +1,50 @@ + \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/BuildEvent.php b/buildscripts/phing/classes/phing/BuildEvent.php new file mode 100644 index 00000000..d4e1ea79 --- /dev/null +++ b/buildscripts/phing/classes/phing/BuildEvent.php @@ -0,0 +1,205 @@ +. + */ + +require_once 'phing/system/lang/EventObject.php'; + +/** + * Encapsulates a build specific event. + * + *

                                                We have three sources of events all handled by this class: + * + *

                                                  + *
                                                • Project level events
                                                • + *
                                                • Target level events
                                                • + *
                                                • Task level events
                                                • + *
                                                + * + *

                                                Events are all fired from the project class by creating an event object + * using this class and passing it to the listeners. + * + * @author Andreas Aderhold + * @author Hans Lellelid + * @version $Revision: 1.10 $ + * @package phing + */ +class BuildEvent extends EventObject { + + /** + * A reference to the project + * @var Project + */ + protected $project; + + /** + * A reference to the target + * @var Target + */ + protected $target; + + /** + * A reference to the task + * + * @var Task + */ + protected $task; + + /** + * The message of this event, if the event is a message + * @var string + * @access private + */ + protected $message = null; + + /** + * The priority of the message + * + * @var string + * @see $message + * @access private + */ + protected $priority = PROJECT_MSG_VERBOSE; + + /** + * The execption that caused the event, if any + * + * @var object + * @access private + */ + protected $exception = null; + + /** + * Construct a BuildEvent for a project, task or target source event + * + * @param object project the project that emitted the event. + * @access public + */ + function __construct($source) { + parent::__construct($source); + if ($source instanceof Project) { + $this->project = $source; + $this->target = null; + $this->task = null; + } elseif ($source instanceof Target) { + $this->project = $source->getProject(); + $this->target = $source; + $this->task = null; + } elseif ($source instanceof Task) { + $this->project = $source->getProject(); + $this->target = $source->getOwningTarget(); + $this->task = $source; + } else { + throw new Exception("Can not construct BuildEvent, unknown source given."); + } + } + + /** + * Sets the message with details and the message priority for this event. + * + * @param string The string message of the event + * @param integer The priority this message should have + */ + function setMessage($message, $priority) { + $this->message = (string) $message; + $this->priority = (int) $priority; + } + + /** + * Set the exception that was the cause of this event. + * + * @param Exception The exception that caused the event + */ + function setException($exception) { + $this->exception = $exception; + } + + /** + * Returns the project instance that fired this event. + * + * The reference to the project instance is set by the constructor if this + * event was fired from the project class. + * + * @return Project The project instance that fired this event + */ + function getProject() { + return $this->project; + } + + /** + * Returns the target instance that fired this event. + * + * The reference to the target instance is set by the constructor if this + * event was fired from the target class. + * + * @return object The target that fired this event + * @access public + */ + function getTarget() { + return $this->target; + } + + /** + * Returns the target instance that fired this event. + * + * The reference to the task instance is set by the constructor if this + * event was fired within a task. + * + * @return object The task that fired this event + * @access public + */ + function getTask() { + return $this->task; + } + + /** + * Returns the logging message. This field will only be set for + * "messageLogged" events. + * + * @return string The log message + * @access public + */ + function getMessage() { + return $this->message; + } + + /** + * Returns the priority of the logging message. This field will only + * be set for "messageLogged" events. + * + * @return integer The message priority + * @access public + */ + function getPriority() { + return $this->priority; + } + + /** + * Returns the exception that was thrown, if any. + * This field will only be set for "taskFinished", "targetFinished", and + * "buildFinished" events. + * + * @see BuildListener::taskFinished() + * @see BuildListener::targetFinished() + * @see BuildListener::buildFinished() + */ + function getException() { + return $this->exception; + } +} diff --git a/buildscripts/phing/classes/phing/BuildException.php b/buildscripts/phing/classes/phing/BuildException.php new file mode 100644 index 00000000..8c108130 --- /dev/null +++ b/buildscripts/phing/classes/phing/BuildException.php @@ -0,0 +1,100 @@ +. + */ + +/** + * BuildException is for when things go wrong in a build execution. + * + * @author Andreas Aderhold + * @version $Revision: 1.12 $ + * @package phing + */ +class BuildException extends Exception { + + /** location in the xml file */ + protected $location = null; + + /** The nested "cause" exception. */ + protected $cause; + + /** + * Construct a BuildException. + * Supported signatures: + * throw new BuildException($causeExc); + * throw new BuildException($msg); + * throw new Buildexception($causeExc, $loc); + * throw new BuildException($msg, $causeExc); + * throw new BuildException($msg, $loc); + * throw new BuildException($msg, $causeExc, $loc); + */ + function __construct($p1, $p2 = null, $p3 = null) { + + $cause = null; + $loc = null; + $msg = ""; + + if ($p3 !== null) { + $cause = $p2; + $loc = $p3; + $msg = $p1; + } elseif ($p2 !== null) { + if ($p2 instanceof Exception) { + $cause = $p2; + $msg = $p1; + } elseif ($p2 instanceof Location) { + $loc = $p2; + if ($p1 instanceof Exception) { + $cause = $p1; + } else { + $msg = $p1; + } + } + } elseif ($p1 instanceof Exception) { + $cause = $p1; + } else { + $msg = $p1; + } + + parent::__construct($msg); + + if ($cause !== null) { + $this->cause = $cause; + $this->message .= " [wrapped: " . $cause->getMessage() ."]"; + } + + if ($loc !== null) { + $this->setLocation($loc); + } + } + + function getCause() { + return $this->cause; + } + + function getLocation() { + return $this->location; + } + + function setLocation($loc) { + $this->location = $loc; + $this->message = $loc->toString() . ': ' . $this->message; + } + +} diff --git a/buildscripts/phing/classes/phing/BuildListener.php b/buildscripts/phing/classes/phing/BuildListener.php new file mode 100644 index 00000000..12a96c7b --- /dev/null +++ b/buildscripts/phing/classes/phing/BuildListener.php @@ -0,0 +1,91 @@ +. + */ + +/** + * Interface for build listeners. + * + * Classes that implement a listener must extend this class and (faux)implement + * all methods that are decleard as dummies below. + * + * @author Andreas Aderhold + * @author Hans Lellelid + * @version $Revision: 1.6 $ + * @see BuildEvent + * @see Project::addBuildListener() + * @package phing + */ +interface BuildListener { + + /** + * Fired before any targets are started. + * + * @param BuildEvent The BuildEvent + */ + function buildStarted(BuildEvent $event); + + /** + * Fired after the last target has finished. + * + * @param BuildEvent The BuildEvent + * @see BuildEvent::getException() + */ + function buildFinished(BuildEvent $event); + + /** + * Fired when a target is started. + * + * @param BuildEvent The BuildEvent + * @see BuildEvent::getTarget() + */ + function targetStarted(BuildEvent $event); + + /** + * Fired when a target has finished. + * + * @param BuildEvent The BuildEvent + * @see BuildEvent#getException() + */ + function targetFinished(BuildEvent $event); + + /** + * Fired when a task is started. + * + * @param BuildEvent The BuildEvent + * @see BuildEvent::getTask() + */ + function taskStarted(BuildEvent $event); + + /** + * Fired when a task has finished. + * + * @param BuildEvent The BuildEvent + * @see BuildEvent::getException() + */ + function taskFinished(BuildEvent $event); + + /** + * Fired whenever a message is logged. + * + * @param BuildEvent The BuildEvent + * @see BuildEvent::getMessage() + */ + function messageLogged(BuildEvent $event); +} diff --git a/buildscripts/phing/classes/phing/IntrospectionHelper.php b/buildscripts/phing/classes/phing/IntrospectionHelper.php new file mode 100644 index 00000000..b4300950 --- /dev/null +++ b/buildscripts/phing/classes/phing/IntrospectionHelper.php @@ -0,0 +1,542 @@ +. + */ + +include_once 'phing/types/Reference.php'; +include_once 'phing/types/Path.php'; +include_once 'phing/util/StringHelper.php'; + +/** + * Helper class that collects the methods that a task or nested element + * holds to set attributes, create nested elements or hold PCDATA + * elements. + * + *

                                                  + *
                                                • SMART-UP INLINE DOCS
                                                • + *
                                                • POLISH-UP THIS CLASS
                                                • + *
                                                + * + * @author Andreas Aderhold + * @author Hans Lellelid + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.19 $ + * @package phing + */ +class IntrospectionHelper { + + + + /** + * Holds the attribute setter methods. + * + * @var array string[] + */ + private $attributeSetters = array(); + + /** + * Holds methods to create nested elements. + * + * @var array string[] + */ + private $nestedCreators = array(); + + /** + * Holds methods to store configured nested elements. + * + * @var array string[] + */ + private $nestedStorers = array(); + + /** + * Map from attribute names to nested types. + */ + private $nestedTypes = array(); + + /** + * New idea in phing: any class can register certain + * keys -- e.g. "task.current_file" -- which can be used in + * task attributes, if supported. In the build XML these + * are referred to like this: + * + * In the type/task a listener method must be defined: + * function setListeningReplace($slot) {} + * @var array string[] + */ + private $slotListeners = array(); + + /** + * The method to add PCDATA stuff. + * + * @var string Method name of the addText (redundant?) method, if class supports it :) + */ + private $methodAddText = null; + + /** + * The Class that's been introspected. + * + * @var object + * @access private + */ + private $bean; + + /** + * The cache of IntrospectionHelper classes instantiated by getHelper(). + * @var array IntrospectionHelpers[] + */ + private static $helpers = array(); + + /** + * Factory method for helper objects. + * + * @param string $class The class to create a Helper for + */ + public static function getHelper($class) { + if (!isset(self::$helpers[$class])) { + self::$helpers[$class] = new IntrospectionHelper($class); + } + return self::$helpers[$class]; + } + + /** + * This function constructs a new introspection helper for a specific class. + * + * This method loads all methods for the specified class and categorizes them + * as setters, creators, slot listeners, etc. This way, the setAttribue() doesn't + * need to perform any introspection -- either the requested attribute setter/creator + * exists or it does not & a BuildException is thrown. + * + * @param string $bean The classname for this IH. + */ + function __construct($class) { + + $this->bean = new ReflectionClass($class); + + //$methods = get_class_methods($bean); + foreach($this->bean->getMethods() as $method) { + + if ($method->isPublic()) { + + // We're going to keep case-insensitive method names + // for as long as we're allowed :) It makes it much + // easier to map XML attributes to PHP class method names. + $name = strtolower($method->getName()); + + // There are a few "reserved" names that might look like attribute setters + // but should actually just be skipped. (Note: this means you can't ever + // have an attribute named "location" or "tasktype" or a nested element named "task".) + if ($name === "setlocation" || $name === "settasktype" || $name === "addtask") { + continue; + } + + if ($name === "addtext") { + + $this->methodAddText = $method; + + } elseif (strpos($name, "setlistening") === 0) { + + // Phing supports something unique called "RegisterSlots" + // These are dynamic values that use a basic slot system so that + // classes can register to listen to specific slots, and the value + // will always be grabbed from the slot (and never set in the project + // component). This is useful for things like tracking the current + // file being processed by a filter (e.g. AppendTask sets an append.current_file + // slot, which can be ready by the XSLTParam type.) + + if (count($method->getParameters()) !== 1) { + throw new BuildException($method->getDeclaringClass()->getName()."::".$method->getName()."() must take exactly one parameter."); + } + + $this->slotListeners[$name] = $method; + + } elseif (strpos($name, "set") === 0) { + + // A standard attribute setter. + + if (count($method->getParameters()) !== 1) { + throw new BuildException($method->getDeclaringClass()->getName()."::".$method->getName()."() must take exactly one parameter."); + } + + $this->attributeSetters[$name] = $method; + + } elseif (strpos($name, "create") === 0) { + + if (count($method->getParameters()) > 0) { + throw new BuildException($method->getDeclaringClass()->getName()."::".$method->getName()."() may not take any parameters."); + } + + // Because PHP doesn't support return types, we are going to do + // two things here to guess return type: + // 1) parse comments for an explicit value + // 2) if that fails, assume that the part of the method after "create" + // is the name of the return type (in many cases it is not) + + // This isn't super important -- i.e. we're not instantaiting classes + // based on this information. It's more just so that IntrospectionHelper + // can keep track of all the nested types -- and provide more helpful + // exception messages, etc. + + preg_match('/@return[\s]+([\w]+)/', $method->getDocComment(), $matches); + if (!empty($matches[1]) && class_exists($matches[1], false)) { + $this->nestedTypes[$name] = $matches[1]; + } else { + // assume that method createEquals() creates object of type "Equals" + // (that example would be false, of course) + $this->nestedTypes[$name] = $this->getPropertyName($name, "create"); + } + + $this->nestedCreators[$name] = $method; + + } elseif (strpos($name, "addconfigured") === 0) { + + // *must* use class hints if using addConfigured ... + + // 1 param only + $params = $method->getParameters(); + + if (count($params) < 1) { + throw new BuildException($method->getDeclaringClass()->getName()."::".$method->getName()."() must take at least one parameter."); + } + + if (count($params) > 1) { + $this->warn($method->getDeclaringClass()->getName()."::".$method->getName()."() takes more than one parameter. (IH only uses the first)"); + } + + $classname = null; + + if (($hint = $params[0]->getClass()) !== null) { + $classname = $hint->getName(); + } + + if ($classname === null) { + throw new BuildException($method->getDeclaringClass()->getName()."::".$method->getName()."() method MUST use a class hint to indicate the class type of parameter."); + } + + $this->nestedTypes[$name] = $classname; + + $this->nestedStorers[$name] = $method; + + } elseif (strpos($name, "add") === 0) { + + // *must* use class hints if using add ... + + // 1 param only + $params = $method->getParameters(); + if (count($params) < 1) { + throw new BuildException($method->getDeclaringClass()->getName()."::".$method->getName()."() must take at least one parameter."); + } + + if (count($params) > 1) { + $this->warn($method->getDeclaringClass()->getName()."::".$method->getName()."() takes more than one parameter. (IH only uses the first)"); + } + + $classname = null; + + if (($hint = $params[0]->getClass()) !== null) { + $classname = $hint->getName(); + } + + // we don't use the classname here, but we need to make sure it exists before + // we later try to instantiate a non-existant class + if ($classname === null) { + throw new BuildException($method->getDeclaringClass()->getName()."::".$method->getName()."() method MUST use a class hint to indicate the class type of parameter."); + } + + $this->nestedCreators[$name] = $method; + } + } // if $method->isPublic() + } // foreach + } + + + /** Sets the named attribute. */ + function setAttribute(Project $project, $element, $attributeName, &$value) { + + // we want to check whether the value we are setting looks like + // a slot-listener variable: %{task.current_file} + // + // slot-listener variables are not like properties, in that they cannot be mixed with + // other text values. The reason for this disparity is that properties are only + // set when first constructing objects from XML, whereas slot-listeners are always dynamic. + // + // This is made possible by PHP5 (objects automatically passed by reference) and PHP's loose + // typing. + + if (StringHelper::isSlotVar($value)) { + + $as = "setlistening" . strtolower($attributeName); + + if (!isset($this->slotListeners[$as])) { + $msg = $this->getElementName($project, $element) . " doesn't support a slot-listening '$attributeName' attribute."; + throw new BuildException($msg); + } + + $method = $this->slotListeners[$as]; + + $key = StringHelper::slotVar($value); + $value = Register::getSlot($key); // returns a RegisterSlot object which will hold current value of that register (accessible using getValue()) + + } else { + + // Traditional value options + + $as = "set".strtolower($attributeName); + + if (!isset($this->attributeSetters[$as])) { + $msg = $this->getElementName($project, $element) . " doesn't support the '$attributeName' attribute."; + throw new BuildException($msg); + } + + $method = $this->attributeSetters[$as]; + + if ($as == "setrefid") { + $value = new Reference($value); + } else { + + // decode any html entities in string + $value = html_entity_decode($value); + + // value is a string representation of a boolean type, + // convert it to primitive + if (StringHelper::isBoolean($value)) { + + $value = StringHelper::booleanValue($value); + } + + // does method expect a PhingFile object? if so, then + // pass a project-relative file. + $params = $method->getParameters(); + + $classname = null; + + if (($hint = $params[0]->getClass()) !== null) { + $classname = $hint->getName(); + } + + // there should only be one param; we'll just assume .... + if ($classname !== null) { + switch(strtolower($classname)) { + case "phingfile": + $value = $project->resolveFile($value); + break; + case "path": + $value = new Path($project, $value); + break; + case "reference": + $value = new Reference($value); + break; + // any other object params we want to support should go here ... + } + + } // if hint !== null + + } // if not setrefid + + } // if is slot-listener + + try { + $project->log(" -calling setter ".$method->getDeclaringClass()->getName()."::".$method->getName()."()", PROJECT_MSG_DEBUG); + $method->invoke($element, $value); + } catch(Exception $exc) { + throw new BuildException($exc); + } + + } + + /** Adds PCDATA areas.*/ + function addText(Project $project, $element, $text) { + if ($this->methodAddText === null) { + $msg = $this->getElementName($project, $element)." doesn't support nested text data."; + throw new BuildException($msg); + } + try { + $method = $this->methodAddText; + $method->invoke($element, $text); + } catch (Exception $exc) { + throw new BuildException($exc); + } + } + + /** + * Creates a named nested element. + * + * Valid creators can be in the form createFoo() or addFoo(Bar). + * @return object Returns the nested element. + * @throws BuildException + */ + function createElement(Project $project, $element, $elementName) { + + $addMethod = "add".strtolower($elementName); + $createMethod = "create".strtolower($elementName); + $nestedElement = null; + + if (isset($this->nestedCreators[$createMethod])) { + + $method = $this->nestedCreators[$createMethod]; + try { // try to invoke the creator method on object + $project->log(" -calling creator ".$method->getDeclaringClass()->getName()."::".$method->getName()."()", PROJECT_MSG_DEBUG); + $nestedElement = $method->invoke($element); + } catch (Exception $exc) { + throw new BuildException($exc); + } + + } elseif (isset($this->nestedCreators[$addMethod])) { + + $method = $this->nestedCreators[$addMethod]; + + // project components must use class hints to support the add methods + + try { // try to invoke the adder method on object + + $project->log(" -calling adder ".$method->getDeclaringClass()->getName()."::".$method->getName()."()", PROJECT_MSG_DEBUG); + // we've already assured that correct num of params + // exist and that method is using class hints + $params = $method->getParameters(); + + $classname = null; + + if (($hint = $params[0]->getClass()) !== null) { + $classname = $hint->getName(); + } + + // create a new instance of the object and add it via $addMethod + $nestedElement = new $classname(); + + $method->invoke($element, $nestedElement); + + } catch (Exception $exc) { + throw new BuildException($exc); + } + } else { + $msg = $this->getElementName($project, $element) . " doesn't support the '$elementName' creator/adder."; + throw new BuildException($msg); + } + + if ($nestedElement instanceof ProjectComponent) { + $nestedElement->setProject($project); + } + + return $nestedElement; + } + + /** + * Creates a named nested element. + * @return void + * @throws BuildException + */ + function storeElement($project, $element, $child, $elementName = null) { + + if ($elementName === null) { + return; + } + + $storer = "addconfigured".strtolower($elementName); + + if (isset($this->nestedStorers[$storer])) { + + $method = $this->nestedStorers[$storer]; + + try { + $project->log(" -calling storer ".$method->getDeclaringClass()->getName()."::".$method->getName()."()", PROJECT_MSG_DEBUG); + $method->invoke($element, $child); + } catch (Exception $exc) { + throw new BuildException($exc); + } + } + + } + + /** Does the introspected class support PCDATA? */ + function supportsCharacters() { + return ($this->methodAddText !== null); + } + + /** Return all attribues supported by the introspected class. */ + function getAttributes() { + $attribs = array(); + foreach (array_keys($this->attributeSetters) as $setter) { + $attribs[] =$this->getPropertyName($setter, "set"); + } + return $attribs; + } + + /** Return all nested elements supported by the introspected class. */ + function getNestedElements() { + return $this->nestedTypes; + } + + /** + * Get the the name for an element. + * When possible the full classnam (phing.tasks.system.PropertyTask) will + * be returned. If not available (loaded in taskdefs or typedefs) then the + * XML element name will be returned. + * + * @param Project $project + * @param object $element The Task or type element. + * @return string Fully qualified class name of element when possible. + */ + function getElementName(Project $project, $element) { + + $taskdefs = $project->getTaskDefinitions(); + $typedefs = $project->getDataTypeDefinitions(); + + // check if class of element is registered with project (tasks & types) + // most element types don't have a getTag() method + $elClass = get_class($element); + + if (!in_array('getTag', get_class_methods($elClass))) { + // loop through taskdefs and typesdefs and see if the class name + // matches (case-insensitive) any of the classes in there + foreach(array_merge($taskdefs, $typedefs) as $elName => $class) { + if (0 === strcasecmp($elClass, StringHelper::unqualify($class))) { + return $class; + } + } + return "$elClass (unknown)"; + } else { + // ->getTag() method does exist, so use it + $elName = $element->getTag(); + if (isset($taskdefs[$elName])) { + return $taskdefs[$elName]; + } elseif (isset($typedefs[$elName])) { + + return $typedefs[$elName]; + } else { + return "$elName (unknown)"; + } + } + } + + /** extract the name of a property from a method name - subtracting a given prefix. */ + function getPropertyName($methodName, $prefix) { + $start = strlen($prefix); + return strtolower(substr($methodName, $start)); + } + + /** + * Prints warning message to screen if -debug was used. + */ + function warn($msg) { + if (Phing::getMsgOutputLevel() === PROJECT_MSG_DEBUG) { + print("[IntrospectionHelper] " . $msg . "\n"); + } + } + +} diff --git a/buildscripts/phing/classes/phing/Phing.php b/buildscripts/phing/classes/phing/Phing.php new file mode 100644 index 00000000..bb8d67f6 --- /dev/null +++ b/buildscripts/phing/classes/phing/Phing.php @@ -0,0 +1,1161 @@ +. + */ + +require_once 'phing/Project.php'; +require_once 'phing/ProjectComponent.php'; +require_once 'phing/Target.php'; +require_once 'phing/Task.php'; + +include_once 'phing/BuildException.php'; +include_once 'phing/BuildEvent.php'; + +include_once 'phing/parser/Location.php'; +include_once 'phing/parser/ExpatParser.php'; +include_once 'phing/parser/AbstractHandler.php'; +include_once 'phing/parser/ProjectConfigurator.php'; +include_once 'phing/parser/RootHandler.php'; +include_once 'phing/parser/ProjectHandler.php'; +include_once 'phing/parser/TaskHandler.php'; +include_once 'phing/parser/TargetHandler.php'; +include_once 'phing/parser/DataTypeHandler.php'; +include_once 'phing/parser/NestedElementHandler.php'; + +include_once 'phing/system/util/Properties.php'; +include_once 'phing/util/StringHelper.php'; +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/system/io/FileReader.php'; +include_once 'phing/system/util/Register.php'; + +/** + * Entry point into Phing. This class handles the full lifecycle of a build -- from + * parsing & handling commandline arguments to assembling the project to shutting down + * and cleaning up in the end. + * + * If you are invoking Phing from an external application, this is still + * the class to use. Your applicaiton can invoke the start() method, passing + * any commandline arguments or additional properties. + * + * @author Andreas Aderhold + * @author Hans Lellelid + * @version $Revision: 1.51 $ + * @package phing + */ +class Phing { + + /** The default build file name */ + const DEFAULT_BUILD_FILENAME = "build.xml"; + + /** Our current message output status. Follows PROJECT_MSG_XXX */ + private static $msgOutputLevel = PROJECT_MSG_INFO; + + /** PhingFile that we are using for configuration */ + private $buildFile = null; + + /** The build targets */ + private $targets = array(); + + /** + * Set of properties that are passed in from commandline or invoking code. + * @var Properties + */ + private static $definedProps; + + /** Names of classes to add as listeners to project */ + private $listeners = array(); + + private $loggerClassname = null; + + /** The class to handle input (can be only one). */ + private $inputHandlerClassname; + + /** Indicates if this phing should be run */ + private $readyToRun = false; + + /** Indicates we should only parse and display the project help information */ + private $projectHelp = false; + + /** Used by utility function getResourcePath() */ + private static $importPaths; + + /** System-wide static properties (moved from System) */ + private static $properties = array(); + + /** Static system timer. */ + private static $timer; + + /** The current Project */ + private static $currentProject; + + /** Whether to capture PHP errors to buffer. */ + private static $phpErrorCapture = false; + + /** Array of captured PHP errors */ + private static $capturedPhpErrors = array(); + + /** + * Prints the message of the Exception if it's not null. + */ + function printMessage(Exception $t) { + print($t->getMessage() . "\n"); + if (self::getMsgOutputLevel() === PROJECT_MSG_DEBUG) { + print($t->getTraceAsString()."\n"); + if ($t instanceof Exception) { + $c = $t->getCause(); + if ($c !== null) { + print("Wrapped exception trace:\n"); + print($c->getTraceAsString() . "\n"); + } + } + } // if output level is DEBUG + } + + /** + * Entry point allowing for more options from other front ends. + * + * This method encapsulates the complete build lifecycle. + * + * @param array &$args The commandline args passed to phing shell script. + * @param array $additionalUserProperties Any additional properties to be passed to Phing (alternative front-end might implement this). + * These additional properties will be available using the getDefinedProperty() method and will + * be added to the project's "user" properties. + * @return void + * @see execute() + * @see runBuild() + */ + public static function start(&$args, $additionalUserProperties = null) { + + try { + $m = new Phing(); + $m->execute($args); + } catch (Exception $exc) { + $m->printMessage($exc); + self::halt(-1); // Parameter error + } + + if ($additionalUserProperties !== null) { + $keys = $m->additionalUserProperties->keys(); + while(count($keys)) { + $key = array_shift($keys); + $property = $m->additionalUserProperties->getProperty($key); + $m->setDefinedProperty($key, $property); + } + } + + try { + $m->runBuild(); + } catch(Exception $exc) { + self::halt(1); // Errors occured + } + + // everything fine, shutdown + self::halt(0); // no errors, everything is cake + } + + /** + * Making output level a static property so that this property + * can be accessed by other parts of the system, enabling + * us to display more information -- e.g. backtraces -- for "debug" level. + * @return int + */ + public static function getMsgOutputLevel() { + return self::$msgOutputLevel; + } + + /** + * Command line entry point. This method kicks off the building + * of a project object and executes a build using either a given + * target or the default target. + * + * @param array $args Command line args. + * @return void + */ + public static function fire($args) { + self::start($args, null); + } + + /** + * Setup/initialize Phing environment from commandline args. + * @param array $args commandline args passed to phing shell. + * @return void + */ + public function execute($args) { + + self::$definedProps = new Properties(); + $this->searchForThis = null; + + // cycle through given args + for ($i = 0, $argcount = count($args); $i < $argcount; ++$i) { + // ++$i intentional here, as first param is script name + $arg = $args[$i]; + + if ($arg == "-help" || $arg == "-h") { + $this->printUsage(); + return; + } elseif ($arg == "-version" || $arg == "-v") { + $this->printVersion(); + return; + } elseif ($arg == "-quiet" || $arg == "-q") { + self::$msgOutputLevel = PROJECT_MSG_WARN; + } elseif ($arg == "-verbose") { + $this->printVersion(); + self::$msgOutputLevel = PROJECT_MSG_VERBOSE; + } elseif ($arg == "-debug") { + $this->printVersion(); + self::$msgOutputLevel = PROJECT_MSG_DEBUG; + } elseif ($arg == "-logfile") { + try { // try to set logfile + if (!isset($args[$i+1])) { + print("You must specify a log file when using the -logfile argument\n"); + return; + } else { + $logFile = new PhingFile($args[++$i]); + $this->loggerClassname = 'phing.listener.PearLogger'; + $this->setDefinedProperty('pear.log.name', $logFile->getAbsolutePath()); + } + } catch (IOException $ioe) { + print("Cannot write on the specified log file. Make sure the path exists and you have write permissions.\n"); + throw $ioe; + } + } elseif ($arg == "-buildfile" || $arg == "-file" || $arg == "-f") { + if (!isset($args[$i+1])) { + print("You must specify a buildfile when using the -buildfile argument\n"); + return; + } else { + $this->buildFile = new PhingFile($args[++$i]); + } + } elseif ($arg == "-listener") { + if (!isset($args[$i+1])) { + print("You must specify a listener class when using the -listener argument\n"); + return; + } else { + $this->listeners[] = $args[++$i]; + } + + } elseif (StringHelper::startsWith("-D", $arg)) { + $name = substr($arg, 2); + $value = null; + $posEq = strpos($name, "="); + if ($posEq !== false) { + $value = substr($name, $posEq+1); + $name = substr($name, 0, $posEq); + } elseif ($i < count($args)-1) { + $value = $args[++$i]; + } + self::$definedProps->setProperty($name, $value); + } elseif ($arg == "-logger") { + if (!isset($args[$i+1])) { + print("You must specify a classname when using the -logger argument\n"); + return; + } else { + $this->loggerClassname = $args[++$i]; + } + } elseif ($arg == "-inputhandler") { + if ($this->inputHandlerClassname !== null) { + throw new BuildException("Only one input handler class may be specified."); + } + if (!isset($args[$i+1])) { + print("You must specify a classname when using the -inputhandler argument\n"); + return; + } else { + $this->inputHandlerClassname = $args[++$i]; + } + } elseif ($arg == "-projecthelp" || $arg == "-targets" || $arg == "-list" || $arg == "-l") { + // set the flag to display the targets and quit + $this->projectHelp = true; + } elseif ($arg == "-find") { + // eat up next arg if present, default to build.xml + if ($i < count($args)-1) { + $this->searchForThis = $args[++$i]; + } else { + $this->searchForThis = self::DEFAULT_BUILD_FILENAME; + } + } elseif (substr($arg,0,1) == "-") { + // we don't have any more args + print("Unknown argument: $arg\n"); + $this->printUsage(); + return; + } else { + // if it's no other arg, it may be the target + array_push($this->targets, $arg); + } + } + + // if buildFile was not specified on the command line, + if ($this->buildFile === null) { + // but -find then search for it + if ($this->searchForThis !== null) { + $this->buildFile = $this->_findBuildFile(self::getProperty("user.dir"), $this->searchForThis); + } else { + $this->buildFile = new PhingFile(self::DEFAULT_BUILD_FILENAME); + } + } + // make sure buildfile exists + if (!$this->buildFile->exists()) { + throw new BuildException("Buildfile: " . $this->buildFile->__toString() . " does not exist!"); + } + + // make sure it's not a directory + if ($this->buildFile->isDirectory()) { + throw new BuildException("Buildfile: " . $this->buildFile->__toString() . " is a dir!"); + } + + $this->readyToRun = true; + } + + /** + * Helper to get the parent file for a given file. + * + * @param PhingFile $file + * @return PhingFile Parent file or null if none + */ + function _getParentFile(PhingFile $file) { + $filename = $file->getAbsolutePath(); + $file = new PhingFile($filename); + $filename = $file->getParent(); + + if ($filename !== null && self::$msgOutputLevel >= PROJECT_MSG_VERBOSE) { + print("Searching in $filename\n"); + } + + return ($filename === null) ? null : new PhingFile($filename); + } + + /** + * Search parent directories for the build file. + * + * Takes the given target as a suffix to append to each + * parent directory in search of a build file. Once the + * root of the file-system has been reached an exception + * is thrown. + * + * @param string $start Start file path. + * @param string $suffix Suffix filename to look for in parents. + * @return PhingFile A handle to the build file + * + * @throws BuildException Failed to locate a build file + */ + function _findBuildFile($start, $suffix) { + if (self::$msgOutputLevel >= PROJECT_MSG_INFO) { + print("Searching for $suffix ...\n"); + } + $startf = new PhingFile($start); + $parent = new PhingFile($startf->getAbsolutePath()); + $file = new PhingFile($parent, $suffix); + + // check if the target file exists in the current directory + while (!$file->exists()) { + // change to parent directory + $parent = $this->_getParentFile($parent); + + // if parent is null, then we are at the root of the fs, + // complain that we can't find the build file. + if ($parent === null) { + throw new BuildException("Could not locate a build file!"); + } + // refresh our file handle + $file = new PhingFile($parent, $suffix); + } + return $file; + } + + /** + * Executes the build. + * @return void + */ + function runBuild() { + + if (!$this->readyToRun) { + return; + } + + $project = new Project(); + + self::setCurrentProject($project); + set_error_handler(array('Phing', 'handlePhpError')); + + $error = null; + + $this->addBuildListeners($project); + $this->addInputHandler($project); + + // set this right away, so that it can be used in logging. + $project->setUserProperty("phing.file", $this->buildFile->getAbsolutePath()); + + try { + $project->fireBuildStarted(); + $project->init(); + } catch (Exception $exc) { + $project->fireBuildFinished($exc); + throw $exc; + } + + $project->setUserProperty("phing.version", $this->getPhingVersion()); + + $e = self::$definedProps->keys(); + while (count($e)) { + $arg = (string) array_shift($e); + $value = (string) self::$definedProps->getProperty($arg); + $project->setUserProperty($arg, $value); + } + unset($e); + + $project->setUserProperty("phing.file", $this->buildFile->getAbsolutePath()); + + // first use the Configurator to create the project object + // from the given build file. + + try { + ProjectConfigurator::configureProject($project, $this->buildFile); + } catch (Exception $exc) { + $project->fireBuildFinished($exc); + restore_error_handler(); + self::unsetCurrentProject(); + throw $exc; + } + + // make sure that we have a target to execute + if (count($this->targets) === 0) { + $this->targets[] = $project->getDefaultTarget(); + } + + // execute targets if help param was not given + if (!$this->projectHelp) { + + try { + $project->executeTargets($this->targets); + } catch (Exception $exc) { + $project->fireBuildFinished($exc); + restore_error_handler(); + self::unsetCurrentProject(); + throw $exc; + } + } + // if help is requested print it + if ($this->projectHelp) { + try { + $this->printDescription($project); + $this->printTargets($project); + } catch (Exception $exc) { + $project->fireBuildFinished($exc); + restore_error_handler(); + self::unsetCurrentProject(); + throw $exc; + } + } + + // finally { + if (!$this->projectHelp) { + $project->fireBuildFinished(null); + } + + restore_error_handler(); + self::unsetCurrentProject(); + } + + /** + * Bind any default build listeners to this project. + * Currently this means adding the logger. + * @param Project $project + * @return void + */ + private function addBuildListeners(Project $project) { + // Add the default listener + $project->addBuildListener($this->createLogger()); + } + + /** + * Creates the InputHandler and adds it to the project. + * + * @param Project $project the project instance. + * + * @throws BuildException if a specified InputHandler + * class could not be loaded. + */ + private function addInputHandler(Project $project) { + if ($this->inputHandlerClassname === null) { + $handler = new DefaultInputHandler(); + } else { + try { + $clz = Phing::import($this->inputHandlerClassname); + $handler = new $clz(); + if ($project !== null && method_exists($handler, 'setProject')) { + $handler->setProject($project); + } + } catch (Exception $e) { + $msg = "Unable to instantiate specified input handler " + . "class " . $this->inputHandlerClassname . " : " + . $e->getMessage(); + throw new BuildException($msg); + } + } + $project->setInputHandler($handler); + } + + /** + * Creates the default build logger for sending build events to the log. + * @return BuildListener The created Logger + */ + private function createLogger() { + if ($this->loggerClassname !== null) { + self::import($this->loggerClassname); + // get class name part + $classname = self::import($this->loggerClassname); + $logger = new $classname; + } else { + require_once 'phing/listener/DefaultLogger.php'; + $logger = new DefaultLogger(); + } + $logger->setMessageOutputLevel(self::$msgOutputLevel); + return $logger; + } + + /** + * Sets the current Project + * @param Project $p + */ + public static function setCurrentProject($p) { + self::$currentProject = $p; + } + + /** + * Unsets the current Project + */ + public static function unsetCurrentProject() { + self::$currentProject = null; + } + + /** + * Gets the current Project. + * @return Project Current Project or NULL if none is set yet/still. + */ + public static function getCurrentProject() { + return self::$currentProject; + } + + /** + * A static convenience method to send a log to the current (last-setup) Project. + * If there is no currently-configured Project, then this will do nothing. + * @param string $message + * @param int $priority PROJECT_MSG_INFO, etc. + */ + public static function log($message, $priority = PROJECT_MSG_INFO) { + $p = self::getCurrentProject(); + if ($p) { + $p->log($message, $priority); + } + } + + /** + * Error handler for PHP errors encountered during the build. + * This uses the logging for the currently configured project. + */ + public static function handlePhpError($level, $message, $file, $line) { + + // don't want to print supressed errors + if (error_reporting() > 0) { + + if (self::$phpErrorCapture) { + + self::$capturedPhpErrors[] = array('message' => $message, 'level' => $level, 'line' => $line, 'file' => $file); + + } else { + + $message = '[PHP Error] ' . $message; + $message .= ' [line ' . $line . ' of ' . $file . ']'; + + switch ($level) { + + case E_STRICT: + case E_NOTICE: + case E_USER_NOTICE: + self::log($message, PROJECT_MSG_VERBOSE); + break; + case E_WARNING: + case E_USER_WARNING: + self::log($message, PROJECT_MSG_WARN); + break; + case E_ERROR: + case E_USER_ERROR: + default: + self::log($message, PROJECT_MSG_ERR); + + } // switch + + } // if phpErrorCapture + + } // if not @ + + } + + /** + * Begins capturing PHP errors to a buffer. + * While errors are being captured, they are not logged. + */ + public static function startPhpErrorCapture() { + self::$phpErrorCapture = true; + self::$capturedPhpErrors = array(); + } + + /** + * Stops capturing PHP errors to a buffer. + * The errors will once again be logged after calling this method. + */ + public static function stopPhpErrorCapture() { + self::$phpErrorCapture = false; + } + + /** + * Clears the captured errors without affecting the starting/stopping of the capture. + */ + public static function clearCapturedPhpErrors() { + self::$capturedPhpErrors = array(); + } + + /** + * Gets any PHP errors that were captured to buffer. + * @return array array('message' => message, 'line' => line number, 'file' => file name, 'level' => error level) + */ + public static function getCapturedPhpErrors() { + return self::$capturedPhpErrors; + } + + /** Prints the usage of how to use this class */ + function printUsage() { + $lSep = self::getProperty("line.separator"); + $msg = ""; + $msg .= "phing [options] [target [target2 [target3] ...]]" . $lSep; + $msg .= "Options: " . $lSep; + $msg .= " -h -help print this message" . $lSep; + $msg .= " -l -list list available targets in this project" . $lSep; + $msg .= " -v -version print the version information and exit" . $lSep; + $msg .= " -q -quiet be extra quiet" . $lSep; + $msg .= " -verbose be extra verbose" . $lSep; + $msg .= " -debug print debugging information" . $lSep; + $msg .= " -logfile use given file for log" . $lSep; + $msg .= " -logger the class which is to perform logging" . $lSep; + $msg .= " -f -buildfile use given buildfile" . $lSep; + $msg .= " -D= use value for given property" . $lSep; + $msg .= " -find search for buildfile towards the root of the" . $lSep; + $msg .= " filesystem and use it" . $lSep; + //$msg .= " -recursive search for buildfile downwards and use it" . $lSep; + $msg .= $lSep; + $msg .= "Report bugs to ".$lSep; + print($msg); + } + + function printVersion() { + print(self::getPhingVersion()."\n"); + } + + function getPhingVersion() { + $versionPath = self::getResourcePath("phing/etc/VERSION.TXT"); + if ($versionPath === null) { + $versionPath = self::getResourcePath("etc/VERSION.TXT"); + } + try { // try to read file + $buffer = null; + $file = new PhingFile($versionPath); + $reader = new FileReader($file); + $reader->readInto($buffer); + $buffer = trim($buffer); + //$buffer = "PHING version 1.0, Released 2002-??-??"; + $phingVersion = $buffer; + } catch (IOException $iox) { + print("Can't read version information file\n"); + throw new BuildException("Build failed"); + } + return $phingVersion; + } + + /** Print the project description, if any */ + function printDescription(Project $project) { + if ($project->getDescription() !== null) { + print($project->getDescription()."\n"); + } + } + + /** Print out a list of all targets in the current buildfile */ + function printTargets($project) { + // find the target with the longest name + $maxLength = 0; + $targets = $project->getTargets(); + $targetNames = array_keys($targets); + $targetName = null; + $targetDescription = null; + $currentTarget = null; + + // split the targets in top-level and sub-targets depending + // on the presence of a description + + $subNames = array(); + $topNameDescMap = array(); + + foreach($targets as $currentTarget) { + $targetName = $currentTarget->getName(); + $targetDescription = $currentTarget->getDescription(); + + // subtargets are targets w/o descriptions + if ($targetDescription === null) { + $subNames[] = $targetName; + } else { + // topNames and topDescriptions are handled later + // here we store in hash map (for sorting purposes) + $topNameDescMap[$targetName] = $targetDescription; + if (strlen($targetName) > $maxLength) { + $maxLength = strlen($targetName); + } + } + } + + // Sort the arrays + sort($subNames); // sort array values, resetting keys (which are numeric) + ksort($topNameDescMap); // sort the keys (targetName) keeping key=>val associations + + $topNames = array_keys($topNameDescMap); + $topDescriptions = array_values($topNameDescMap); + + $defaultTarget = $project->getDefaultTarget(); + + if ($defaultTarget !== null && $defaultTarget !== "") { + $defaultName = array(); + $defaultDesc = array(); + $defaultName[] = $defaultTarget; + + $indexOfDefDesc = array_search($defaultTarget, $topNames, true); + if ($indexOfDefDesc !== false && $indexOfDefDesc >= 0) { + $defaultDesc = array(); + $defaultDesc[] = $topDescriptions[$indexOfDefDesc]; + } + + $this->_printTargets($defaultName, $defaultDesc, "Default target:", $maxLength); + + } + $this->_printTargets($topNames, $topDescriptions, "Main targets:", $maxLength); + $this->_printTargets($subNames, null, "Subtargets:", 0); + } + + /** + * Writes a formatted list of target names with an optional description. + * + * @param array $names The names to be printed. + * Must not be null. + * @param array $descriptions The associated target descriptions. + * May be null, in which case + * no descriptions are displayed. + * If non-null, this should have + * as many elements as names. + * @param string $heading The heading to display. + * Should not be null. + * @param int $maxlen The maximum length of the names of the targets. + * If descriptions are given, they are padded to this + * position so they line up (so long as the names really + * are shorter than this). + */ + private function _printTargets($names, $descriptions, $heading, $maxlen) { + $lSep = self::getProperty("line.separator"); + $spaces = ' '; + while (strlen($spaces) < $maxlen) { + $spaces .= $spaces; + } + $msg = ""; + $msg .= $heading . $lSep; + $msg .= str_repeat("-",79) . $lSep; + + $total = count($names); + for($i=0; $i < $total; $i++) { + $msg .= " "; + $msg .= $names[$i]; + if (!empty($descriptions)) { + $msg .= substr($spaces, 0, $maxlen - strlen($names[$i]) + 2); + $msg .= $descriptions[$i]; + } + $msg .= $lSep; + } + if ($total > 0) { + print $msg . $lSep; + } + } + + /** + * Import a dot-path notation class path. + * @param string $dotPath + * @param mixed $classpath String or object supporting __toString() + * @return string The unqualified classname (which can be instantiated). + * @throws BuildException - if cannot find the specified file + */ + public static function import($dotPath, $classpath = null) { + + // first check to see that the class specified hasn't already been included. + // (this also handles case where this method is called w/ a classname rather than dotpath) + $classname = StringHelper::unqualify($dotPath); + if (class_exists($classname, false)) { + return $classname; + } + + $dotClassname = basename($dotPath); + $dotClassnamePos = strlen($dotPath) - strlen($dotClassname); + $classFile = strtr($dotClassname, '.', DIRECTORY_SEPARATOR) . ".php"; + $path = substr_replace($dotPath, $classFile, $dotClassnamePos); + + Phing::__import($path, $classpath); + + return $classname; + } + + /** + * Import a PHP file + * @param string $path Path to the PHP file + * @param mixed $classpath String or object supporting __toString() + * @throws BuildException - if cannot find the specified file + */ + public static function __import($path, $classpath = null) { + + if ($classpath) { + + // Apparently casting to (string) no longer invokes __toString() automatically. + if (is_object($classpath)) { + $classpath = $classpath->__toString(); + } + + // classpaths are currently additive, but we also don't want to just + // indiscriminantly prepand/append stuff to the include_path. This means + // we need to parse current incldue_path, and prepend any + // specified classpath locations that are not already in the include_path. + // + // NOTE: the reason why we do it this way instead of just changing include_path + // and then changing it back, is that in many cases applications (e.g. Propel) will + // include/require class files from within method calls. This means that not all + // necessary files will be included in this import() call, and hence we can't + // change the include_path back without breaking those apps. While this method could + // be more expensive than switching & switching back (not sure, but maybe), it makes it + // possible to write far less expensive run-time applications (e.g. using Propel), which is + // really where speed matters more. + + $curr_parts = explode(PATH_SEPARATOR, ini_get('include_path')); + $add_parts = explode(PATH_SEPARATOR, $classpath); + $new_parts = array_diff($add_parts, $curr_parts); + if ($new_parts) { + if (self::getMsgOutputLevel() === PROJECT_MSG_DEBUG) { + print("Phing::import() prepending new include_path components: " . implode(PATH_SEPARATOR, $new_parts) . "\n"); + } + ini_set('include_path', implode(PATH_SEPARATOR, array_merge($new_parts, $curr_parts))); + } + } + + $ret = include_once($path); + + if ($ret === false) { + $e = new BuildException("Error importing $path"); + if (self::getMsgOutputLevel() === PROJECT_MSG_DEBUG) { + // We can't log this because listeners belong + // to projects. We'll just print it -- of course + // that isn't very compatible w/ other frontends (but + // there aren't any right now, so I'm not stressing) + print("Error importing $path\n"); + print($e->getTraceAsString()."\n"); + } + throw $e; + } + + return; + } + + /** + * Looks on include path for specified file. + * @return string File found (null if no file found). + */ + public static function getResourcePath($path) { + + if (self::$importPaths === null) { + $paths = ini_get("include_path"); + self::$importPaths = explode(PATH_SEPARATOR, ini_get("include_path")); + } + + $path = str_replace('\\', DIRECTORY_SEPARATOR, $path); + $path = str_replace('/', DIRECTORY_SEPARATOR, $path); + + foreach (self::$importPaths as $prefix) { + $foo_path = $prefix . DIRECTORY_SEPARATOR . $path; + if (file_exists($foo_path)) { + return $foo_path; + } + } + + // Check for the property phing.home + $home_dir = self::getProperty('phing.home'); + + if ($home_dir) + { + $home_path = $home_dir . DIRECTORY_SEPARATOR . $path; + + if (file_exists($home_path)) + { + return $home_path; + } + } + + // If we are using this via PEAR then check for the file in the data dir + // This is a bit of a hack, but works better than previous solution of assuming + // data_dir is on the include_path. + $data_dir = '@DATA-DIR@'; + if ($data_dir{0} != '@') { // if we're using PEAR then the @ DATA-DIR @ token will have been substituted. + $data_path = $data_dir . DIRECTORY_SEPARATOR . $path; + if (file_exists($data_path)) { + return $data_path; + } + } + + return null; + } + + // ------------------------------------------------------------------------------------------- + // System-wide methods (moved from System class, which had namespace conflicts w/ PEAR System) + // ------------------------------------------------------------------------------------------- + + /** + * Set System constants which can be retrieved by calling Phing::getProperty($propName). + * @return void + */ + private static function setSystemConstants() { + + /* + * PHP_OS returns on + * WindowsNT4.0sp6 => WINNT + * Windows2000 => WINNT + * Windows ME => WIN32 + * Windows 98SE => WIN32 + * FreeBSD 4.5p7 => FreeBSD + * Redhat Linux => Linux + * Mac OS X => Darwin + */ + self::setProperty('host.os', PHP_OS); + + // this is used by some tasks too + self::setProperty('os.name', PHP_OS); + + // it's still possible this won't be defined, + // e.g. if Phing is being included in another app w/o + // using the phing.php script. + if (!defined('PHP_CLASSPATH')) { + define('PHP_CLASSPATH', get_include_path()); + } + + self::setProperty('php.classpath', PHP_CLASSPATH); + + // try to determine the host filesystem and set system property + // used by Fileself::getFileSystem to instantiate the correct + // abstraction layer + + switch (strtoupper(PHP_OS)) { + case 'WINNT': + self::setProperty('host.fstype', 'WINNT'); + break; + case 'WIN32': + self::setProperty('host.fstype', 'WIN32'); + break; + default: + self::setProperty('host.fstype', 'UNIX'); + break; + } + + self::setProperty('php.version', PHP_VERSION); + self::setProperty('user.home', getenv('HOME')); + self::setProperty('application.startdir', getcwd()); + self::setProperty('line.separator', "\n"); + + // try to detect machine dependent information + $sysInfo = array(); + if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN' && function_exists("posix_uname")) { + $sysInfo = posix_uname(); + } else { + $sysInfo['nodename'] = php_uname('n'); + $sysInfo['machine']= php_uname('m') ; + //this is a not so ideal substition, but maybe better than nothing + $sysInfo['domain'] = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : "unknown"; + $sysInfo['release'] = php_uname('r'); + $sysInfo['version'] = php_uname('v'); + } + + + self::setProperty("host.name", isset($sysInfo['nodename']) ? $sysInfo['nodename'] : "unknown"); + self::setProperty("host.arch", isset($sysInfo['machine']) ? $sysInfo['machine'] : "unknown"); + self::setProperty("host.domain",isset($sysInfo['domain']) ? $sysInfo['domain'] : "unknown"); + self::setProperty("host.os.release", isset($sysInfo['release']) ? $sysInfo['release'] : "unknown"); + self::setProperty("host.os.version", isset($sysInfo['version']) ? $sysInfo['version'] : "unknown"); + unset($sysInfo); + } + + /** + * This gets a property that was set via command line or otherwise passed into Phing. + * "Defined" in this case means "externally defined". The reason this method exists is to + * provide a public means of accessing commandline properties for (e.g.) logger or listener + * scripts. E.g. to specify which logfile to use, PearLogger needs to be able to access + * the pear.log.name property. + * + * @param string $name + * @return string value of found property (or null, if none found). + */ + public static function getDefinedProperty($name) { + return self::$definedProps->getProperty($name); + } + + /** + * This sets a property that was set via command line or otherwise passed into Phing. + * + * @param string $name + * @return string value of found property (or null, if none found). + */ + public static function setDefinedProperty($name, $value) { + return self::$definedProps->setProperty($name, $value); + } + + /** + * Returns property value for a System property. + * System properties are "global" properties like line.separator, + * and user.dir. Many of these correspond to similar properties in Java + * or Ant. + * + * @param string $paramName + * @return string Value of found property (or null, if none found). + */ + public static function getProperty($propName) { + + // some properties are detemined on each access + // some are cached, see below + + // default is the cached value: + $val = isset(self::$properties[$propName]) ? self::$properties[$propName] : null; + + // special exceptions + switch($propName) { + case 'user.dir': + $val = getcwd(); + break; + } + + return $val; + } + + /** Retuns reference to all properties*/ + public static function &getProperties() { + return self::$properties; + } + + public static function setProperty($propName, $propValue) { + $propName = (string) $propName; + $oldValue = self::getProperty($propName); + self::$properties[$propName] = $propValue; + return $oldValue; + } + + public static function currentTimeMillis() { + list($usec, $sec) = explode(" ",microtime()); + return ((float)$usec + (float)$sec); + } + + /** + * Sets the include path based on PHP_CLASSPATH constant (set in phing.php). + * @return void + */ + private static function setIncludePaths() { + $success = false; + + if (defined('PHP_CLASSPATH')) { + $success = ini_set('include_path', PHP_CLASSPATH); + } else { + // don't do anything, just assume that include_path has been properly set. + $success = true; + } + + if ($success === false) { + print("SYSTEM FAILURE: Could not set PHP include path\n"); + self::halt(-1); + } + } + + /** + * Sets PHP INI values that Phing needs. + * @return void + */ + private static function setIni() { + error_reporting(E_ALL); + set_time_limit(0); + ini_set('magic_quotes_gpc', 'off'); + ini_set('short_open_tag', 'off'); + ini_set('default_charset', 'iso-8859-1'); + ini_set('register_globals', 'off'); + ini_set('allow_call_time_pass_reference', 'on'); + + // should return memory limit in MB + $mem_limit = (int) ini_get('memory_limit'); + if ($mem_limit < 32) { + ini_set('memory_limit', '32M'); // nore: this may need to be higher for many projects + } + } + + /** + * Returns reference to Timer object. + * @return Timer + */ + public static function getTimer() { + if (self::$timer === null) { + include_once 'phing/system/util/Timer.php'; + self::$timer= new Timer(); + } + return self::$timer; + } + + /** + * Start up Phing. + * Sets up the Phing environment -- does NOT initiate the build process. + * @return void + */ + public static function startup() { + + register_shutdown_function(array('Phing', 'shutdown')); + + // some init stuff + self::getTimer()->start(); + + self::setSystemConstants(); + self::setIncludePaths(); + self::setIni(); + } + + /** + * Halts the system. + * @see shutdown() + */ + public static function halt($code=0) { + self::shutdown($code); + } + + /** + * Stops timers & exits. + * @return void + */ + public static function shutdown($exitcode = 0) { + //print("[AUTOMATIC SYSTEM SHUTDOWN]\n"); + self::getTimer()->stop(); + exit($exitcode); // final point where everything stops + } + +} diff --git a/buildscripts/phing/classes/phing/Project.php b/buildscripts/phing/classes/phing/Project.php new file mode 100644 index 00000000..8123d91e --- /dev/null +++ b/buildscripts/phing/classes/phing/Project.php @@ -0,0 +1,966 @@ +. + */ + +define('PROJECT_MSG_DEBUG', 4); +define('PROJECT_MSG_VERBOSE', 3); +define('PROJECT_MSG_INFO', 2); +define('PROJECT_MSG_WARN', 1); +define('PROJECT_MSG_ERR', 0); + +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/util/FileUtils.php'; +include_once 'phing/TaskAdapter.php'; +include_once 'phing/util/StringHelper.php'; +include_once 'phing/BuildEvent.php'; +include_once 'phing/input/DefaultInputHandler.php'; + +/** + * The Phing project class. Represents a completely configured Phing project. + * The class defines the project and all tasks/targets. It also contains + * methods to start a build as well as some properties and FileSystem + * abstraction. + * + * @author Andreas Aderhold + * @author Hans Lellelid + * @version $Revision: 1.29 $ + * @package phing + */ +class Project { + + /** contains the targets */ + private $targets = array(); + /** global filterset (future use) */ + private $globalFilterSet = array(); + /** all globals filters (future use) */ + private $globalFilters = array(); + + /** Project properties map (usually String to String). */ + private $properties = array(); + + /** + * Map of "user" properties (as created in the Ant task, for example). + * Note that these key/value pairs are also always put into the + * project properties, so only the project properties need to be queried. + * Mapping is String to String. + */ + private $userProperties = array(); + + /** + * Map of inherited "user" properties - that are those "user" + * properties that have been created by tasks and not been set + * from the command line or a GUI tool. + * Mapping is String to String. + */ + private $inheritedProperties = array(); + + /** task definitions for this project*/ + private $taskdefs = array(); + + /** type definitions for this project */ + private $typedefs = array(); + + /** holds ref names and a reference to the referred object*/ + private $references = array(); + + /** The InputHandler being used by this project. */ + private $inputHandler; + + /* -- properties that come in via xml attributes -- */ + + /** basedir (PhingFile object) */ + private $basedir; + + /** the default target name */ + private $defaultTarget = 'all'; + + /** project name (required) */ + private $name; + + /** project description */ + private $description; + + /** a FileUtils object */ + private $fileUtils; + + /** Build listeneers */ + private $listeners = array(); + + /** + * Constructor, sets any default vars. + */ + function __construct() { + $this->fileUtils = new FileUtils(); + $this->inputHandler = new DefaultInputHandler(); + } + + /** + * Sets the input handler + */ + public function setInputHandler(InputHandler $handler) { + $this->inputHandler = $handler; + } + + /** + * Retrieves the current input handler. + */ + public function getInputHandler() { + return $this->inputHandler; + } + + /** inits the project, called from main app */ + function init() { + // set builtin properties + $this->setSystemProperties(); + + // load default tasks + $taskdefs = Phing::getResourcePath("phing/tasks/defaults.properties"); + + try { // try to load taskdefs + $props = new Properties(); + $in = new PhingFile((string)$taskdefs); + + if ($in === null) { + throw new BuildException("Can't load default task list"); + } + $props->load($in); + + $enum = $props->propertyNames(); + foreach($enum as $key) { + $value = $props->getProperty($key); + $this->addTaskDefinition($key, $value); + } + } catch (IOException $ioe) { + throw new BuildException("Can't load default task list"); + } + + // load default tasks + $typedefs = Phing::getResourcePath("phing/types/defaults.properties"); + + try { // try to load typedefs + $props = new Properties(); + $in = new PhingFile((string)$typedefs); + if ($in === null) { + throw new BuildException("Can't load default datatype list"); + } + $props->load($in); + + $enum = $props->propertyNames(); + foreach($enum as $key) { + $value = $props->getProperty($key); + $this->addDataTypeDefinition($key, $value); + } + } catch(IOException $ioe) { + throw new BuildException("Can't load default datatype list"); + } + } + + /** returns the global filterset (future use) */ + function getGlobalFilterSet() { + return $this->globalFilterSet; + } + + // --------------------------------------------------------- + // Property methods + // --------------------------------------------------------- + + /** + * Sets a property. Any existing property of the same name + * is overwritten, unless it is a user property. + * @param string $name The name of property to set. + * Must not be null. + * @param string $value The new value of the property. + * Must not be null. + * @return void + */ + public function setProperty($name, $value) { + + // command line properties take precedence + if (isset($this->userProperties[$name])) { + $this->log("Override ignored for user property " . $name, PROJECT_MSG_VERBOSE); + return; + } + + if (isset($this->properties[$name])) { + $this->log("Overriding previous definition of property " . $name, PROJECT_MSG_VERBOSE); + } + + $this->log("Setting project property: " . $name . " -> " . $value, PROJECT_MSG_DEBUG); + $this->properties[$name] = $value; + } + + /** + * Sets a property if no value currently exists. If the property + * exists already, a message is logged and the method returns with + * no other effect. + * + * @param string $name The name of property to set. + * Must not be null. + * @param string $value The new value of the property. + * Must not be null. + * @since 2.0 + */ + public function setNewProperty($name, $value) { + if (isset($this->properties[$name])) { + $this->log("Override ignored for property " . $name, PROJECT_MSG_DEBUG); + return; + } + $this->log("Setting project property: " . $name . " -> " . $value, PROJECT_MSG_DEBUG); + $this->properties[$name] = $value; + } + + /** + * Sets a user property, which cannot be overwritten by + * set/unset property calls. Any previous value is overwritten. + * @param string $name The name of property to set. + * Must not be null. + * @param string $value The new value of the property. + * Must not be null. + * @see #setProperty() + */ + public function setUserProperty($name, $value) { + $this->log("Setting ro project property: " . $name . " -> " . $value, PROJECT_MSG_DEBUG); + $this->userProperties[$name] = $value; + $this->properties[$name] = $value; + } + + /** + * Sets a user property, which cannot be overwritten by set/unset + * property calls. Any previous value is overwritten. Also marks + * these properties as properties that have not come from the + * command line. + * + * @param string $name The name of property to set. + * Must not be null. + * @param string $value The new value of the property. + * Must not be null. + * @see #setProperty() + */ + public function setInheritedProperty($name, $value) { + $this->inheritedProperties[$name] = $value; + $this->setUserProperty($name, $value); + } + + /** + * Sets a property unless it is already defined as a user property + * (in which case the method returns silently). + * + * @param name The name of the property. + * Must not be null. + * @param value The property value. Must not be null. + */ + private function setPropertyInternal($name, $value) { + if (isset($this->userProperties[$name])) { + $this->log("Override ignored for user property " . $name, PROJECT_MSG_VERBOSE); + return; + } + $this->properties[$name] = $value; + } + + /** + * Returns the value of a property, if it is set. + * + * @param string $name The name of the property. + * May be null, in which case + * the return value is also null. + * @return string The property value, or null for no match + * or if a null name is provided. + */ + public function getProperty($name) { + if (!isset($this->properties[$name])) { + return null; + } + return $this->properties[$name]; + } + + /** + * Replaces ${} style constructions in the given value with the + * string value of the corresponding data types. + * + * @param value The string to be scanned for property references. + * May be null. + * + * @return the given string with embedded property names replaced + * by values, or null if the given string is + * null. + * + * @exception BuildException if the given value has an unclosed + * property name, e.g. ${xxx + */ + public function replaceProperties($value) { + return ProjectConfigurator::replaceProperties($this, $value, $this->properties); + } + + /** + * Returns the value of a user property, if it is set. + * + * @param string $name The name of the property. + * May be null, in which case + * the return value is also null. + * @return string The property value, or null for no match + * or if a null name is provided. + */ + public function getUserProperty($name) { + if (!isset($this->userProperties[$name])) { + return null; + } + return $this->userProperties[$name]; + } + + /** + * Returns a copy of the properties table. + * @return array A hashtable containing all properties + * (including user properties). + */ + public function getProperties() { + return $this->properties; + } + + /** + * Returns a copy of the user property hashtable + * @return a hashtable containing just the user properties + */ + public function getUserProperties() { + return $this->userProperties; + } + + /** + * Copies all user properties that have been set on the command + * line or a GUI tool from this instance to the Project instance + * given as the argument. + * + *

                                                To copy all "user" properties, you will also have to call + * {@link #copyInheritedProperties copyInheritedProperties}.

                                                + * + * @param Project $other the project to copy the properties to. Must not be null. + * @return void + * @since phing 2.0 + */ + public function copyUserProperties(Project $other) { + foreach($this->userProperties as $arg => $value) { + if (isset($this->inheritedProperties[$arg])) { + continue; + } + $other->setUserProperty($arg, $value); + } + } + + /** + * Copies all user properties that have not been set on the + * command line or a GUI tool from this instance to the Project + * instance given as the argument. + * + *

                                                To copy all "user" properties, you will also have to call + * {@link #copyUserProperties copyUserProperties}.

                                                + * + * @param other the project to copy the properties to. Must not be null. + * + * @since phing 2.0 + */ + public function copyInheritedProperties(Project $other) { + foreach($this->userProperties as $arg => $value) { + if ($other->getUserProperty($arg) !== null) { + continue; + } + $other->setInheritedProperty($arg, $value); + } + } + + // --------------------------------------------------------- + // END Properties methods + // --------------------------------------------------------- + + + function setDefaultTarget($targetName) { + $this->defaultTarget = (string) trim($targetName); + } + + function getDefaultTarget() { + return (string) $this->defaultTarget; + } + + /** + * Sets the name of the current project + * + * @param string name of project + * @return void + * @access public + * @author Andreas Aderhold, andi@binarycloud.com + */ + + function setName($name) { + $this->name = (string) trim($name); + $this->setProperty("phing.project.name", $this->name); + } + + /** + * Returns the name of this project + * + * @returns string projectname + * @access public + * @author Andreas Aderhold, andi@binarycloud.com + */ + function getName() { + return (string) $this->name; + } + + /** Set the projects description */ + function setDescription($description) { + $this->description = (string) trim($description); + } + + /** return the description, null otherwise */ + function getDescription() { + return $this->description; + } + + /** Set basedir object from xml*/ + function setBasedir($dir) { + if ($dir instanceof PhingFile) { + $dir = $dir->getAbsolutePath(); + } + + $dir = $this->fileUtils->normalize($dir); + + $dir = new PhingFile((string) $dir); + if (!$dir->exists()) { + throw new BuildException("Basedir ".$dir->getAbsolutePath()." does not exist"); + } + if (!$dir->isDirectory()) { + throw new BuildException("Basedir ".$dir->getAbsolutePath()." is not a directory"); + } + $this->basedir = $dir; + $this->setPropertyInternal("project.basedir", $this->basedir->getAbsolutePath()); + $this->log("Project base dir set to: " . $this->basedir->getPath(), PROJECT_MSG_VERBOSE); + + // [HL] added this so that ./ files resolve correctly. This may be a mistake ... or may be in wrong place. + chdir($dir->getAbsolutePath()); + } + + /** + * Returns the basedir of this project + * + * @returns PhingFile Basedir PhingFile object + * @access public + * @throws BuildException + * @author Andreas Aderhold, andi@binarycloud.com + */ + function getBasedir() { + if ($this->basedir === null) { + try { // try to set it + $this->setBasedir("."); + } catch (BuildException $exc) { + throw new BuildException("Can not set default basedir. ".$exc->getMessage()); + } + } + return $this->basedir; + } + + /** + * Sets system properties and the environment variables for this project. + * + * @return void + */ + function setSystemProperties() { + + // first get system properties + $systemP = array_merge( self::getProperties(), Phing::getProperties() ); + foreach($systemP as $name => $value) { + $this->setPropertyInternal($name, $value); + } + + // and now the env vars + foreach($_SERVER as $name => $value) { + // skip arrays + if (is_array($value)) { + continue; + } + $this->setPropertyInternal('env.' . $name, $value); + } + return true; + } + + + /** + * Adds a task definition. + * @param string $name Name of tag. + * @param string $class The class path to use. + * @param string $classpath The classpat to use. + */ + function addTaskDefinition($name, $class, $classpath = null) { + $name = $name; + $class = $class; + if ($class === "") { + $this->log("Task $name has no class defined.", PROJECT_MSG_ERR); + } elseif (!isset($this->taskdefs[$name])) { + Phing::import($class, $classpath); + $this->taskdefs[$name] = $class; + $this->log(" +Task definiton: $name ($class)", PROJECT_MSG_DEBUG); + } else { + $this->log("Task $name ($class) already registerd, skipping", PROJECT_MSG_VERBOSE); + } + } + + function &getTaskDefinitions() { + return $this->taskdefs; + } + + /** + * Adds a data type definition. + * @param string $name Name of tag. + * @param string $class The class path to use. + * @param string $classpath The classpat to use. + */ + function addDataTypeDefinition($typeName, $typeClass, $classpath = null) { + if (!isset($this->typedefs[$typeName])) { + Phing::import($typeClass, $classpath); + $this->typedefs[$typeName] = $typeClass; + $this->log(" +User datatype: $typeName ($typeClass)", PROJECT_MSG_DEBUG); + } else { + $this->log("Type $name ($class) already registerd, skipping", PROJECT_MSG_VERBOSE); + } + } + + function getDataTypeDefinitions() { + return $this->typedefs; + } + + /** add a new target to the project */ + function addTarget($targetName, &$target) { + if (isset($this->targets[$targetName])) { + throw new BuildException("Duplicate target: $targetName"); + } + $this->addOrReplaceTarget($targetName, $target); + } + + function addOrReplaceTarget($targetName, &$target) { + $this->log(" +Target: $targetName", PROJECT_MSG_DEBUG); + $target->setProject($this); + $this->targets[$targetName] = $target; + } + + function getTargets() { + return $this->targets; + } + + /** + * Create a new task instance and return reference to it. This method is + * sorta factory like. A _local_ instance is created and a reference returned to + * that instance. Usually PHP destroys local variables when the function call + * ends. But not if you return a reference to that variable. + * This is kinda error prone, because if no reference exists to the variable + * it is destroyed just like leaving the local scope with primitive vars. There's no + * central place where the instance is stored as in other OOP like languages. + * + * [HL] Well, ZE2 is here now, and this is still working. We'll leave this alone + * unless there's any good reason not to. + * + * @param string $taskType Task name + * @returns Task A task object + * @throws BuildException + * Exception + */ + function createTask($taskType) { + try { + $cls = ""; + $tasklwr = strtolower($taskType); + foreach ($this->taskdefs as $name => $class) { + if (strtolower($name) === $tasklwr) { + $cls = StringHelper::unqualify($class); + break; + } + } + + if ($cls === "") { + return null; + } + + if (!class_exists($cls)) { + throw new BuildException("Could not instantiate class $cls, even though a class was specified. (Make sure that the specified class file contains a class with the correct name.)"); + } + + $o = new $cls(); + + if ($o instanceof Task) { + $task = $o; + } else { + $this->log (" (Using TaskAdapter for: $taskType)", PROJECT_MSG_DEBUG); + // not a real task, try adapter + $taskA = new TaskAdapter(); + $taskA->setProxy($o); + $task = $taskA; + } + $task->setProject($this); + $task->setTaskType($taskType); + // set default value, can be changed by the user + $task->setTaskName($taskType); + $this->log (" +Task: " . $taskType, PROJECT_MSG_DEBUG); + } catch (Exception $t) { + throw new BuildException("Could not create task of type: " . $taskType, $t); + } + // everything fine return reference + return $task; + } + + /** + * Create a task instance and return reference to it + * See createTask() for explanation how this works + * + * @param string Type name + * @returns object A datatype object + * @throws BuildException + * Exception + */ + function createDataType($typeName) { + try { + $cls = ""; + $typelwr = strtolower($typeName); + foreach ($this->typedefs as $name => $class) { + if (strtolower($name) === $typelwr) { + $cls = StringHelper::unqualify($class); + break; + } + } + + if ($cls === "") { + return null; + } + + if (!class_exists($cls)) { + throw new BuildException("Could not instantiate class $cls, even though a class was specified. (Make sure that the specified class file contains a class with the correct name.)"); + } + + $type = new $cls(); + $this->log(" +Type: $typeName", PROJECT_MSG_DEBUG); + if (!($type instanceof DataType)) { + throw new Exception("$class is not an instance of phing.types.DataType"); + } + if ($type instanceof ProjectComponent) { + $type->setProject($this); + } + } catch (Exception $t) { + throw new BuildException("Could not create type: $typeName", $t); + } + // everything fine return reference + return $type; + } + + /** + * Executes a list of targets + * + * @param array List of target names to execute + * @returns void + * @throws BuildException + */ + function executeTargets($targetNames) { + foreach($targetNames as $tname) { + $this->executeTarget($tname); + } + } + + /** + * Executes a target + * + * @param string Name of Target to execute + * @returns void + * @throws BuildException + */ + function executeTarget($targetName) { + + // complain about executing void + if ($targetName === null) { + throw new BuildException("No target specified"); + } + + // invoke topological sort of the target tree and run all targets + // until targetName occurs. + $sortedTargets = $this->_topoSort($targetName, $this->targets); + + $curIndex = (int) 0; + $curTarget = null; + do { + try { + $curTarget = $sortedTargets[$curIndex++]; + $curTarget->performTasks(); + } catch (BuildException $exc) { + $this->log("Execution of target \"".$curTarget->getName()."\" failed for the following reason: ".$exc->getMessage(), PROJECT_MSG_ERR); + throw $exc; + } + } while ($curTarget->getName() !== $targetName); + } + + + function resolveFile($fileName, $rootDir = null) { + if ($rootDir === null) { + return $this->fileUtils->resolveFile($this->basedir, $fileName); + } else { + return $this->fileUtils->resolveFile($rootDir, $fileName); + } + } + + /** + * Topologically sort a set of Targets. + * @param $root is the (String) name of the root Target. The sort is + * created in such a way that the sequence of Targets until the root + * target is the minimum possible such sequence. + * @param $targets is a array representing a "name to Target" mapping + * @return An array of Strings with the names of the targets in + * sorted order. + */ + function _topoSort($root, &$targets) { + + $root = (string) $root; + $ret = array(); + $state = array(); + $visiting = array(); + + // We first run a DFS based sort using the root as the starting node. + // This creates the minimum sequence of Targets to the root node. + // We then do a sort on any remaining unVISITED targets. + // This is unnecessary for doing our build, but it catches + // circular dependencies or missing Targets on the entire + // dependency tree, not just on the Targets that depend on the + // build Target. + + $this->_tsort($root, $targets, $state, $visiting, $ret); + + $retHuman = ""; + for ($i=0, $_i=count($ret); $i < $_i; $i++) { + $retHuman .= $ret[$i]->toString()." "; + } + $this->log("Build sequence for target '$root' is: $retHuman", PROJECT_MSG_VERBOSE); + + $keys = array_keys($targets); + while($keys) { + $curTargetName = (string) array_shift($keys); + if (!isset($state[$curTargetName])) { + $st = null; + } else { + $st = (string) $state[$curTargetName]; + } + + if ($st === null) { + $this->_tsort($curTargetName, $targets, $state, $visiting, $ret); + } elseif ($st === "VISITING") { + throw new Exception("Unexpected node in visiting state: $curTargetName"); + } + } + + $retHuman = ""; + for ($i=0,$_i=count($ret); $i < $_i; $i++) { + $retHuman .= $ret[$i]->toString()." "; + } + $this->log("Complete build sequence is: $retHuman", PROJECT_MSG_VERBOSE); + + return $ret; + } + + // one step in a recursive DFS traversal of the target dependency tree. + // - The array "state" contains the state (VISITED or VISITING or null) + // of all the target names. + // - The stack "visiting" contains a stack of target names that are + // currently on the DFS stack. (NB: the target names in "visiting" are + // exactly the target names in "state" that are in the VISITING state.) + // 1. Set the current target to the VISITING state, and push it onto + // the "visiting" stack. + // 2. Throw a BuildException if any child of the current node is + // in the VISITING state (implies there is a cycle.) It uses the + // "visiting" Stack to construct the cycle. + // 3. If any children have not been VISITED, tsort() the child. + // 4. Add the current target to the Vector "ret" after the children + // have been visited. Move the current target to the VISITED state. + // "ret" now contains the sorted sequence of Targets upto the current + // Target. + + function _tsort($root, &$targets, &$state, &$visiting, &$ret) { + $state[$root] = "VISITING"; + $visiting[] = $root; + + if (!isset($targets[$root]) || !($targets[$root] instanceof Target)) { + $target = null; + } else { + $target = $targets[$root]; + } + + // make sure we exist + if ($target === null) { + $sb = "Target '$root' does not exist in this project."; + array_pop($visiting); + if (!empty($visiting)) { + $parent = (string) $visiting[count($visiting)-1]; + $sb .= "It is used from target '$parent'."; + } + throw new BuildException($sb); + } + + $deps = $target->getDependencies(); + + while($deps) { + $cur = (string) array_shift($deps); + if (!isset($state[$cur])) { + $m = null; + } else { + $m = (string) $state[$cur]; + } + if ($m === null) { + // not been visited + $this->_tsort($cur, $targets, $state, $visiting, $ret); + } elseif ($m == "VISITING") { + // currently visiting this node, so have a cycle + throw $this->_makeCircularException($cur, $visiting); + } + } + + $p = (string) array_pop($visiting); + if ($root !== $p) { + throw new Exception("Unexpected internal error: expected to pop $root but got $p"); + } + + $state[$root] = "VISITED"; + $ret[] = $target; + } + + function _makeCircularException($end, $stk) { + $sb = "Circular dependency: $end"; + do { + $sb .= " <- ".(string) array_pop($stk); + } while($c != $end); + return new BuildException($sb); + } + + /** + * Adds a reference to an object. This method is called when the parser + * detects a id="foo" attribute. It passes the id as $name and a reference + * to the object assigned to this id as $value + */ + function addReference($name, $object) { + if (isset($this->references[$name])) { + $this->log("Overriding previous definition of reference to $name", PROJECT_MSG_WARN); + } + $this->log("Adding reference: $name -> ".get_class($object), PROJECT_MSG_DEBUG); + $this->references[$name] = $object; + } + + /** + * Returns the references array. + * @return array + */ + function getReferences() { + return $this->references; + } + + /** + * Returns a specific reference. + * @param string $key The reference id/key. + * @return object or null if not defined + */ + function getReference($key) + { + if (isset($this->references[$key])) { + return $this->references[$key]; + } + return null; // just to be explicit + } + + /** + * Abstracting and simplifyling Logger calls for project messages + */ + function log($msg, $level = PROJECT_MSG_INFO) { + $this->logObject($this, $msg, $level); + } + + function logObject($obj, $msg, $level) { + $this->fireMessageLogged($obj, $msg, $level); + } + + function addBuildListener(BuildListener $listener) { + $this->listeners[] = $listener; + } + + function removeBuildListener(BuildListener $listener) { + $newarray = array(); + for ($i=0, $size=count($this->listeners); $i < $size; $i++) { + if ($this->listeners[$i] !== $listener) { + $newarray[] = $this->listeners[$i]; + } + } + $this->listeners = $newarray; + } + + function getBuildListeners() { + return $this->listeners; + } + + function fireBuildStarted() { + $event = new BuildEvent($this); + foreach($this->listeners as $listener) { + $listener->buildStarted($event); + } + } + + function fireBuildFinished($exception) { + $event = new BuildEvent($this); + $event->setException($exception); + foreach($this->listeners as $listener) { + $listener->buildFinished($event); + } + } + + function fireTargetStarted($target) { + $event = new BuildEvent($target); + foreach($this->listeners as $listener) { + $listener->targetStarted($event); + } + } + + function fireTargetFinished($target, $exception) { + $event = new BuildEvent($target); + $event->setException($exception); + foreach($this->listeners as $listener) { + $listener->targetFinished($event); + } + } + + function fireTaskStarted($task) { + $event = new BuildEvent($task); + foreach($this->listeners as $listener) { + $listener->taskStarted($event); + } + } + + function fireTaskFinished($task, $exception) { + $event = new BuildEvent($task); + $event->setException($exception); + foreach($this->listeners as $listener) { + $listener->taskFinished($event); + } + } + + function fireMessageLoggedEvent($event, $message, $priority) { + $event->setMessage($message, $priority); + foreach($this->listeners as $listener) { + $listener->messageLogged($event); + } + } + + function fireMessageLogged($object, $message, $priority) { + $this->fireMessageLoggedEvent(new BuildEvent($object), $message, $priority); + } +} diff --git a/buildscripts/phing/classes/phing/ProjectComponent.php b/buildscripts/phing/classes/phing/ProjectComponent.php new file mode 100644 index 00000000..97ef329f --- /dev/null +++ b/buildscripts/phing/classes/phing/ProjectComponent.php @@ -0,0 +1,72 @@ +. + */ + +/** + * Abstract class providing properties and methods common to all + * the project components + * + * @author Andreas Aderhold + * @author Hans Lellelid + * @version $Revision: 1.5 $ + * @package phing + */ +abstract class ProjectComponent { + + /** + * Holds a reference to the project that a project component + * (a task, a target, etc.) belongs to + * + * @var object A reference to the current project instance + */ + protected $project = null; + + /** + * References the project to the current component. + * + * @param object The reference to the current project + * @access public + */ + function setProject($project) { + $this->project = $project; + } + + /** + * Returns a reference to current project + * + * @return object Reference to current porject object + * @access public + */ + function getProject() { + return $this->project; + } + + /** + * Logs a message with the given priority. + * + * @param string The message to be logged. + * @param integer The message's priority at this message should have + */ + public function log($msg, $level = PROJECT_MSG_INFO) { + if ($this->project !== null) { + $this->project->log($msg, $level); + } + } +} diff --git a/buildscripts/phing/classes/phing/RuntimeConfigurable.php b/buildscripts/phing/classes/phing/RuntimeConfigurable.php new file mode 100644 index 00000000..a23437fa --- /dev/null +++ b/buildscripts/phing/classes/phing/RuntimeConfigurable.php @@ -0,0 +1,118 @@ +. + */ + +/** + * Wrapper class that holds the attributes of a Task (or elements + * nested below that level) and takes care of configuring that element + * at runtime. + * + * SMART-UP INLINE DOCS + * + * @author Andreas Aderhold + * @author Hans Lellelid + * @version $Revision: 1.6 $ + * @package phing + */ +class RuntimeConfigurable { + + private $elementTag = null; + private $children = array(); + private $wrappedObject = null; + private $attributes = array(); + private $characters = ""; + + + /** @param proxy The element to wrap. */ + function __construct($proxy, $elementTag) { + $this->wrappedObject = $proxy; + $this->elementTag = $elementTag; + } + + function setProxy($proxy) { + $this->wrappedObject = $proxy; + } + + /** Set's the attributes for the wrapped element. */ + function setAttributes($attributes) { + $this->attributes = $attributes; + } + + /** Returns the AttributeList of the wrapped element. */ + function getAttributes() { + return $this->attributes; + } + + /** Adds child elements to the wrapped element. */ + function addChild(RuntimeConfigurable $child) { + $this->children[] = $child; + } + + /** Returns the child with index */ + function getChild($index) { + return $this->children[(int)$index]; + } + + /** Add characters from #PCDATA areas to the wrapped element. */ + function addText($data) { + $this->characters .= (string) $data; + } + + function getElementTag() { + return $this->elementTag; + } + + + /** Configure the wrapped element and all children. */ + function maybeConfigure(Project $project) { + $id = null; + + // DataType configured in ProjectConfigurator + // if ( is_a($this->wrappedObject, "DataType") ) + // return; + + if ($this->attributes || $this->characters) { + ProjectConfigurator::configure($this->wrappedObject, $this->attributes, $project); + + if (isset($this->attributes["id"])) { + $id = $this->attributes["id"]; + } + + $this->attributes = null; + + if ($this->characters) { + ProjectConfigurator::addText($project, $this->wrappedObject, (string) $this->characters); + $this->characters=""; + } + if ($id !== null) { + $project->addReference($id, $this->wrappedObject); + } + } + + if ( is_array($this->children) && !empty($this->children) ) { + // Configure all child of this object ... + foreach($this->children as $child) { + $child->maybeConfigure($project); + ProjectConfigurator::storeChild($project, $this->wrappedObject, $child->wrappedObject, strtolower($child->getElementTag())); + } + } + } +} + diff --git a/buildscripts/phing/classes/phing/Target.php b/buildscripts/phing/classes/phing/Target.php new file mode 100644 index 00000000..9aeb9440 --- /dev/null +++ b/buildscripts/phing/classes/phing/Target.php @@ -0,0 +1,317 @@ +. + */ + +include_once 'phing/TaskContainer.php'; + +/** + * The Target component. Carries all required target data. Implements the + * abstract class {@link TaskContainer} + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.10 $ $Date: 2005/10/04 19:13:44 $ + * @access public + * @see TaskContainer + * @package phing + */ + +class Target implements TaskContainer { + + /** name of target */ + private $name; + + /** dependencies */ + private $dependencies = array(); + + /** holds objects of children of this target */ + private $children = array(); + + /** the if cond. from xml */ + private $ifCondition = ""; + + /** the unless cond. from xml */ + private $unlessCondition = ""; + + /** description of this target */ + private $description; + + /** reference to project */ + private $project; + + /** + * References the project to the current component. + * + * @param Project The reference to the current project + */ + public function setProject(Project $project) { + $this->project = $project; + } + + /** + * Returns reference to current project + * + * @return Project Reference to current porject object + */ + public function getProject() { + return $this->project; + } + + /** + * Sets the target dependencies from xml + * + * @param string $depends Comma separated list of targetnames that depend on + * this target + * @throws BuildException + */ + public function setDepends($depends) { + // explode should be faster than strtok + $deps = explode(',', $depends); + for ($i=0, $size=count($deps); $i < $size; $i++) { + $trimmed = trim($deps[$i]); + if ($trimmed === "") { + throw new BuildException("Syntax Error: Depend attribute for target ".$this->getName()." is malformed."); + } + $this->addDependency($trimmed); + } + } + + /** + * Adds a singular dependent target name to the list + * + * @param string The dependency target to add + * @access public + */ + public function addDependency($dependency) { + $this->dependencies[] = (string) $dependency; + } + + /** + * Returns reference to indexed array of the dependencies this target has. + * + * @return array Referece to target dependencoes + */ + public function getDependencies() { + return $this->dependencies; + } + + /** + * Sets the name of the target + * + * @param string Name of this target + */ + public function setName($name) { + $this->name = (string) $name; + } + + /** + * Returns name of this target. + * + * @return string The name of the target + * @access public + */ + function getName() { + return (string) $this->name; + } + + /** + * Adds a task element to the list of this targets child elements + * + * @param object The task object to add + * @access public + */ + function addTask(Task $task) { + $this->children[] = $task; + } + + /** + * Adds a runtime configurable element to the list of this targets child + * elements. + * + * @param object The RuntimeConfigurabel object + * @access public + */ + function addDataType($rtc) { + $this->children[] = $rtc; + } + + /** + * Returns an array of all tasks this target has as childrens. + * + * The task objects are copied here. Don't use this method to modify + * task objects. + * + * @return array Task[] + */ + public function getTasks() { + $tasks = array(); + for ($i=0,$size=count($this->children); $i < $size; $i++) { + $tsk = $this->children[$i]; + if ($tsk instanceof Task) { + // note: we're copying objects here! + $tasks[] = clone $tsk; + } + } + return $tasks; + } + + /** + * Set the if-condition from the XML tag, if any. The property name given + * as parameter must be present so the if condition evaluates to true + * + * @param string The property name that has to be present + * @access public + */ + public function setIf($property) { + $this->ifCondition = ($property === null) ? "" : $property; + } + + /** + * Set the unless-condition from the XML tag, if any. The property name + * given as parameter must be present so the unless condition evaluates + * to true + * + * @param string The property name that has to be present + * @access public + */ + public function setUnless($property) { + $this->unlessCondition = ($property === null) ? "" : $property; + } + + /** + * Sets a textual description of this target. + * + * @param string The description text + */ + public function setDescription($description) { + if ($description !== null && strcmp($description, "") !== 0) { + $this->description = (string) $description; + } else { + $this->description = null; + } + } + + /** + * Returns the description of this target. + * + * @return string The description text of this target + */ + public function getDescription() { + return $this->description; + } + + /** + * Returns a string representation of this target. In our case it + * simply returns the target name field + * + * @return string The string representation of this target + */ + function toString() { + return (string) $this->name; + } + + /** + * The entry point for this class. Does some checking, then processes and + * performs the tasks for this target. + * + */ + public function main() { + if ($this->testIfCondition() && $this->testUnlessCondition()) { + foreach($this->children as $o) { + if ($o instanceof Task) { + // child is a task + $o->perform(); + } else { + // child is a RuntimeConfigurable + $o->maybeConfigure($this->project); + } + } + } elseif (!$this->testIfCondition()) { + $this->project->log("Skipped target '".$this->name."' because property '".$this->ifCondition."' not set.", PROJECT_MSG_VERBOSE); + } else { + $this->project->log("Skipped target '".$this->name."' because property '".$this->unlessCondition."' set.", PROJECT_MSG_VERBOSE); + } + } + + /** + * Performs the tasks by calling the main method of this target that + * actually executes the tasks. + * + * This method is for ZE2 and used for proper exception handling of + * task exceptions. + */ + public function performTasks() { + try {// try to execute this target + $this->project->fireTargetStarted($this); + $this->main(); + $this->project->fireTargetFinished($this, $null=null); + } catch (Exception $exc) { + // log here and rethrow + $this->project->fireTargetFinished($this, $exc); + throw $exc; + } + } + + /** + * Tests if the property set in ifConfiditon exists. + * + * @return boolean true if the property specified + * in $this->ifCondition exists; + * false otherwise + */ + private function testIfCondition() { + if ($this->ifCondition === "") { + return true; + } + + $properties = explode(",", $this->ifCondition); + + $result = true; + foreach ($properties as $property) { + $test = ProjectConfigurator::replaceProperties($this->getProject(), $property, $this->project->getProperties()); + $result = $result && ($this->project->getProperty($test) !== null); + } + + return $result; + } + + /** + * Tests if the property set in unlessCondition exists. + * + * @return boolean true if the property specified + * in $this->unlessCondition exists; + * false otherwise + */ + private function testUnlessCondition() { + if ($this->unlessCondition === "") { + return true; + } + + $properties = explode(",", $this->unlessCondition); + + $result = true; + foreach ($properties as $property) { + $test = ProjectConfigurator::replaceProperties($this->getProject(), $property, $this->project->getProperties()); + $result = $result && ($this->project->getProperty($test) === null); + } + return $result; + } + +} diff --git a/buildscripts/phing/classes/phing/Task.php b/buildscripts/phing/classes/phing/Task.php new file mode 100644 index 00000000..893a82e9 --- /dev/null +++ b/buildscripts/phing/classes/phing/Task.php @@ -0,0 +1,266 @@ +. + */ + +require_once 'phing/ProjectComponent.php'; +include_once 'phing/RuntimeConfigurable.php'; + +/** + * The base class for all Tasks. + * + * Use {@link Project#createTask} to register a new Task. + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.11 $ + * @see Project#createTask() + * @package phing + */ +abstract class Task extends ProjectComponent { + + /** owning Target object */ + protected $target; + + /** description of the task */ + protected $description; + + /** internal taskname (req) */ + protected $taskType; + + /** taskname for logger */ + protected $taskName; + + /** stored buildfile location */ + protected $location; + + /** wrapper of the task */ + protected $wrapper; + + /** + * Sets the owning target this task belongs to. + * + * @param object Reference to owning target + * @access public + */ + function setOwningTarget(Target $target) { + $this->target = $target; + } + + /** + * Returns the owning target of this task. + * + * @return object The target object that owns this task + * @access public + */ + function getOwningTarget() { + return $this->target; + } + + /** + * Returns the name of task, used only for log messages + * + * @return string Name of this task + * @access public + */ + function getTaskName() { + if ($this->taskName === null) { + // if no task name is set, then it's possible + // this task was created from within another task. We don't + // therefore know the XML tag name for this task, so we'll just + // use the class name stripped of "task" suffix. This is only + // for log messages, so we don't have to worry much about accuracy. + return preg_replace('/task$/i', '', get_class($this)); + } + return $this->taskName; + } + + /** + * Sets the name of this task for log messages + * + * @return string A string representing the name of this task for log + * @access public + */ + function setTaskName($name) { + $this->taskName = (string) $name; + } + + /** + * Returns the name of the task under which it was invoked, + * usually the XML tagname + * + * @return string The type of this task (XML Tag) + */ + function getTaskType() { + return $this->taskType; + } + + /** + * Sets the type of the task. Usually this is the name of the XML tag + * + * @param string The type of this task (XML Tag) + */ + function setTaskType($name) { + $this->taskType = (string) $name; + } + + /** + * Returns a name + * + */ + protected function getRegisterSlot($slotName) { + return Register::getSlot('task.' . $this->getTaskName() . '.' . $slotName); + } + + /** + * Provides a project level log event to the task. + * + * @param string The message to log + * @param integer The priority of the message + * @see BuildEvent + * @see BuildListener + */ + function log($msg, $level = PROJECT_MSG_INFO) { + $this->project->logObject($this, $msg, $level); + } + + /** + * Sets a textual description of the task + * + * @param string The text describing the task + */ + public function setDescription($desc) { + $this->description = $desc; + } + + /** + * Returns the textual description of the task + * + * @return string The text description of the task + */ + public function getDescription() { + return $this->description; + } + + /** + * Called by the parser to let the task initialize properly. + * Should throw a BuildException if something goes wrong with the build + * + * This is abstract here, but may not be overloaded by subclasses. + * + * @throws BuildException + */ + public function init() { + } + + /** + * Called by the project to let the task do it's work. This method may be + * called more than once, if the task is invoked more than once. For + * example, if target1 and target2 both depend on target3, then running + * phing target1 target2 will run all tasks in target3 twice. + * + * Should throw a BuildException if someting goes wrong with the build + * + * This is abstract here. Must be overloaded by real tasks. + * + * @access public + */ + abstract function main(); + + /** + * Returns the location within the buildfile this task occurs. Used + * by {@link BuildException} to give detailed error messages. + * + * @return Location The location object describing the position of this + * task within the buildfile. + */ + function getLocation() { + return $this->location; + } + + /** + * Sets the location within the buildfile this task occurs. Called by + * the parser to set location information. + * + * @return object The location object describing the position of this + * task within the buildfile. + * @access public + */ + function setLocation(Location $location) { + $this->location = $location; + } + + /** + * Returns the wrapper object for runtime configuration + * + * @return object The wrapper object used by this task + * @access public + */ + function getRuntimeConfigurableWrapper() { + if ($this->wrapper === null) { + $this->wrapper = new RuntimeConfigurable($this, $this->getTaskName()); + } + return $this->wrapper; + } + + /** + * Sets the wrapper object this task should use for runtime + * configurable elements. + * + * @param object The wrapper object this task should use + * @access public + */ + function setRuntimeConfigurableWrapper(RuntimeConfigurable $wrapper) { + $this->wrapper = $wrapper; + } + + /** + * Configure this task if it hasn't been done already. + * + * @access public + */ + function maybeConfigure() { + if ($this->wrapper !== null) { + $this->wrapper->maybeConfigure($this->project); + } + } + + /** + * Perfrom this task + * + * @access public + */ + function perform() { + + try { // try executing task + $this->project->fireTaskStarted($this); + $this->maybeConfigure(); + $this->main(); + $this->project->fireTaskFinished($this, $null=null); + } catch (Exception $exc) { + if ($exc instanceof BuildException) { + if ($exc->getLocation() === null) { + $exc->setLocation($this->getLocation()); + } + } + $this->project->fireTaskFinished($this, $exc); + throw $exc; + } + } +} diff --git a/buildscripts/phing/classes/phing/TaskAdapter.php b/buildscripts/phing/classes/phing/TaskAdapter.php new file mode 100644 index 00000000..8b84b768 --- /dev/null +++ b/buildscripts/phing/classes/phing/TaskAdapter.php @@ -0,0 +1,84 @@ +. + */ + +require_once 'phing/Task.php'; + +/** + * Use introspection to "adapt" an arbitrary ( not extending Task, but with + * similar patterns). + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.7 $ + * @package phing + */ +class TaskAdapter extends Task { + + /** target object */ + private $proxy; + + /** + * Main entry point. + * @return void + */ + function main() { + + if (method_exists($this->proxy, "setProject")) { + try { // try to set project + $this->proxy->setProject($this->project); + } catch (Exception $ex) { + $this->log("Error setting project in " . get_class($this->proxy) . PROJECT_MSG_ERR); + throw new BuildException($ex); + } + } else { + throw new Exception("Error setting project in class " . get_class($this->proxy)); + } + + if (method_exists($this->proxy, "main")) { + try { //try to call main + $this->proxy->main($this->project); + } catch (Exception $ex) { + $this->log("Error in " . get_class($this->proxy), PROJECT_MSG_ERR); + throw new BuildException($ex->getMessage()); + } + } else { + throw new BuildException("Your task-like class '" . get_class($this->proxy) ."' does not have a main() method"); + } + } + + /** + * Set the target object. + * @param object $o + * @return void + */ + function setProxy($o) { + $this->proxy = $o; + } + + /** + * Gets the target object. + * @return object + */ + function getProxy() { + return $this->proxy; + } + +} diff --git a/buildscripts/phing/classes/phing/TaskContainer.php b/buildscripts/phing/classes/phing/TaskContainer.php new file mode 100644 index 00000000..2e9eb67a --- /dev/null +++ b/buildscripts/phing/classes/phing/TaskContainer.php @@ -0,0 +1,42 @@ +. + */ + +/** + * Abstract interface for objects which can contain tasks (targets) + * Used to check if a class can contain tasks (via instanceof) + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.5 $ $Date: 2005/10/04 19:13:44 $ + * @access public + * @package phing + */ +interface TaskContainer { + + /** + * Adds a task to this task container. Must be implemented + * by derived class + * + * @param object The task to be added to the container + * @access public + */ + function addTask(Task $task); +} diff --git a/buildscripts/phing/classes/phing/UnknownElement.php b/buildscripts/phing/classes/phing/UnknownElement.php new file mode 100644 index 00000000..745130dc --- /dev/null +++ b/buildscripts/phing/classes/phing/UnknownElement.php @@ -0,0 +1,211 @@ +. + */ + +require_once 'phing/Task.php'; + +/** + * Wrapper class that holds all information necessary to create a task + * that did not exist when Phing started. + * + * This has something to do with phing encountering an task XML element + * it is not aware of at start time. This is a situation where special steps + * need to be taken so that the element is then known. + * + * @author Andreas Aderhold + * @author Hans Lellelid + * @version $Revision: 1.9 $ + * @package phing + */ +class UnknownElement extends Task { + + private $elementName; + private $realThing; + private $children = array(); + + /** + * Constructs a UnknownElement object + * + * @param string The XML element name that is unknown + * @access public + */ + function __construct($elementName) { + $this->elementName = (string) $elementName; + } + + /** + * Return the XML element name that this UnnownElement + * handles. + * + * @return string The XML element name that is unknown + */ + public function getTag() { + return (string) $this->elementName; + } + + /** + * Tries to configure the unknown element + * + * @throws BuildException if the element can not be configured + */ + public function maybeConfigure() { + + $this->realThing = $this->makeObject($this, $this->wrapper); + $this->wrapper->setProxy($this->realThing); + if ($this->realThing instanceof Task) { + $this->realThing->setRuntimeConfigurableWrapper($this->wrapper); + } + + $this->handleChildren($this->realThing, $this->wrapper); + $this->wrapper->maybeConfigure($this->getProject()); + + } + + /** + * Called when the real task has been configured for the first time. + * + * @throws BuildException if the task can not be created + */ + public function main() { + + if ($this->realThing === null) { + // plain impossible to get here, maybeConfigure should + // have thrown an exception. + throw new BuildException("Should not be executing UnknownElement::main() -- task/type: {$this->elementName}"); + } + + if ($this->realThing instanceof Task) { + $this->realThing->main(); + } + + } + + /** + * Add a child element to the unknown element + * + * @param object The object representing the child element + */ + public function addChild(UnknownElement $child) { + $this->children[] = $child; + } + + /** + * Handle child elemets of the unknown element, if any. + * + * @param ProjectComponent The parent object the unkown element belongs to + * @param object The parent wrapper object + */ + function handleChildren(ProjectComponent $parent, $parentWrapper) { + + if ($parent instanceof TaskAdapter) { + $parent = $parent->getProxy(); + } + + $parentClass = get_class($parent); + $ih = IntrospectionHelper::getHelper($parentClass); + + for ($i=0, $childrenCount=count($this->children); $i < $childrenCount; $i++) { + + $childWrapper = $parentWrapper->getChild($i); + $child = $this->children[$i]; + $realChild = null; + if ($parent instanceof TaskContainer) { + $realChild = $this->makeTask($child, $childWrapper, false); + $parent->addTask($realChild); + } else { + $realChild = $ih->createElement($this->project, $parent, $child->getTag()); + } + + $childWrapper->setProxy($realChild); + if ($realChild instanceof Task) { + $realChild->setRuntimeConfigurableWrapper($childWrapper); + } + + $child->handleChildren($realChild, $childWrapper); + if ($realChild instanceof Task) { + $realChild->maybeConfigure(); + } + } + } + + /** + * Creates a named task or data type. If the real object is a task, + * it is configured up to the init() stage. + * + * @param UnknownElement $ue The unknown element to create the real object for. + * Must not be null. + * @param RuntimeConfigurable $w Ignored in this implementation. + * @return object The Task or DataType represented by the given unknown element. + */ + protected function makeObject(UnknownElement $ue, RuntimeConfigurable $w) { + $o = $this->makeTask($ue, $w, true); + if ($o === null) { + $o = $this->project->createDataType($ue->getTag()); + } + if ($o === null) { + throw new BuildException("Could not create task/type: '".$ue->getTag()."'. Make sure that this class has been declared using taskdef / typedef."); + } + return $o; + } + + /** + * Create a named task and configure it up to the init() stage. + * + * @param UnknownElement $ue The unknwon element to create a task from + * @param RuntimeConfigurable $w The wrapper object + * @param boolean $onTopLevel Whether to treat this task as if it is top-level. + * @return Task The freshly created task + */ + protected function makeTask(UnknownElement $ue, RuntimeConfigurable $w, $onTopLevel = false) { + + $task = $this->project->createTask($ue->getTag()); + + if ($task === null) { + if (!$onTopLevel) { + throw new BuildException("Could not create task of type: '".$this->elementName."'. Make sure that this class has been declared using taskdef."); + } + return null; + } + + // used to set the location within the xmlfile so that exceptions can + // give detailed messages + + $task->setLocation($this->getLocation()); + $attrs = $w->getAttributes(); + if (isset($attrs['id'])) { + $this->project->addReference($attrs['id'], $task); + } + + // UnknownElement always has an associated target + $task->setOwningTarget($this->target); + + $task->init(); + return $task; + } + + /** + * Get the name of the task to use in logging messages. + * + * @return string The task's name + */ + function getTaskName() { + return $this->realThing === null ? parent::getTaskName() : $this->realThing->getTaskName(); + } +} diff --git a/buildscripts/phing/classes/phing/filters/BaseFilterReader.php b/buildscripts/phing/classes/phing/filters/BaseFilterReader.php new file mode 100644 index 00000000..c9f8c619 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/BaseFilterReader.php @@ -0,0 +1,157 @@ +. +*/ + +include_once 'phing/system/io/FilterReader.php'; +include_once 'phing/system/io/StringReader.php'; + + +/** + * Base class for core filter readers. + * + * @author Yannick Lecaillez + * @version $Revision: 1.8 $ $Date: 2004/05/20 02:24:10 $ + * @access public + * @see FilterReader + * @package phing.filters + */ +class BaseFilterReader extends FilterReader { + + /** Have the parameters passed been interpreted? */ + protected $initialized = false; + + /** The Phing project this filter is part of. */ + protected $project = null; + + /** + * Constructor used by Phing's introspection mechanism. + * The original filter reader is only used for chaining + * purposes, never for filtering purposes (and indeed + * it would be useless for filtering purposes, as it has + * no real data to filter). ChainedReaderHelper uses + * this placeholder instance to create a chain of real filters. + * + * @param Reader $in + */ + function __construct($in = null) { + if ($in === null) { + $dummy = ""; + $in = new StringReader($dummy); + } + parent::__construct($in); + } + + /** + * Returns the initialized status. + * + * @return boolean whether or not the filter is initialized + */ + function getInitialized() { + return $this->initialized; + } + + /** + * Sets the initialized status. + * + * @param boolean $initialized Whether or not the filter is initialized. + */ + function setInitialized($initialized) { + $this->initialized = (boolean) $initialized; + } + + /** + * Sets the project to work with. + * + * @param object $project The project this filter is part of. + * Should not be null. + */ + function setProject(Project $project) { + // type check, error must never occur, bad code of it does + $this->project = $project; + } + + /** + * Returns the project this filter is part of. + * + * @return object The project this filter is part of + */ + function getProject() { + return $this->project; + } + + /** + * Reads characters. + * + * @param off Offset at which to start storing characters. + * @param len Maximum number of characters to read. + * + * @return Characters read, or -1 if the end of the stream + * has been reached + * + * @throws IOException If an I/O error occurs + */ + function read($len = null) { + return $this->in->read($len); + } + + /** + * Reads a line of text ending with '\n' (or until the end of the stream). + * The returned String retains the '\n'. + * + * @return the line read, or null if the end of the + stream has already been reached + * + * @throws IOException if the underlying reader throws one during + * reading + */ + function readLine() { + $line = null; + + while ( ($ch = $this->in->read(1)) !== -1 ) { + $line .= $ch; + if ( $ch === "\n" ) + break; + } + + return $line; + } + + /** + * Returns whether the end of file has been reached with input stream. + * @return boolean + */ + function eof() { + return $this->in->eof(); + } + + /** + * Convenience method to support logging in filters. + * @param string $msg Message to log. + * @param int $level Priority level. + */ + function log($msg, $level = PROJECT_MSG_INFO) { + if ($this->project !== null) { + $this->project->log("[filter:".get_class($this)."] ".$msg, $level); + } + } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/BaseParamFilterReader.php b/buildscripts/phing/classes/phing/filters/BaseParamFilterReader.php new file mode 100644 index 00000000..3d767b40 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/BaseParamFilterReader.php @@ -0,0 +1,69 @@ +. +*/ + +include_once 'phing/filters/BaseFilterReader.php'; +include_once 'phing/types/Parameterizable.php'; +include_once 'phing/types/Parameter.php'; + +/** + * Base class for core filter readers. + * + * @author Yannick Lecaillez + * @copyright © 2003 seasonfive. All rights reserved + * @version $Revision: 1.5 $ $Date: 2005/02/27 20:52:08 $ + * @access public + * @see FilterReader + * @package phing.filters + */ +class BaseParamFilterReader extends BaseFilterReader implements Parameterizable { + + /** The passed in parameter array. */ + protected $_parameters = array(); + + /* + * Sets the parameters used by this filter, and sets + * the filter to an uninitialized status. + * + * @param array Array of parameters to be used by this filter. + * Should not be null. + */ + function setParameters($parameters) { + // type check, error must never occur, bad code of it does + if ( !is_array($parameters) ) { + throw new Exception("Expected parameters array got something else"); + } + + $this->_parameters = $parameters; + $this->setInitialized(false); + } + + /* + * Returns the parameters to be used by this filter. + * + * @return the parameters to be used by this filter + */ + function &getParameters() { + return $this->_parameters; + } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/ChainableReader.php b/buildscripts/phing/classes/phing/filters/ChainableReader.php new file mode 100644 index 00000000..c7de07c4 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/ChainableReader.php @@ -0,0 +1,42 @@ +. +*/ + +/** + * Interface indicating that a reader may be chained to another one. + * + * @author Magesh Umasankar + */ +interface ChainableReader { + + /** + * Returns a reader with the same configuration as this one, + * but filtering input from the specified reader. + * + * @param Reader $rdr the reader which the returned reader should be filtering + * + * @return Reader A reader with the same configuration as this one, but + * filtering input from the specified reader + */ + public function chain(Reader $rdr); +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/ExpandProperties.php b/buildscripts/phing/classes/phing/filters/ExpandProperties.php new file mode 100644 index 00000000..dfd98cc8 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/ExpandProperties.php @@ -0,0 +1,82 @@ +. +*/ + +require_once 'phing/filters/BaseFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Expands Phing Properties, if any, in the data. + *

                                                + * Example:
                                                + *

                                                + * Or: + *
                                                .
                                                +*/
                                                +
                                                +include_once 'phing/filters/BaseParamFilterReader.php';
                                                +include_once 'phing/filters/ChainableReader.php';
                                                +
                                                +/**
                                                + * Reads the first n lines of a stream.
                                                + * (Default is first 10 lines.)
                                                + * 

                                                + * Example: + *

                                                + * Or: + *
                                                
                                                + *    
                                                + * 
                                                + * + * @author Yannick Lecaillez + * @author hans lellelid, hans@velum.net + * @version $Revision: 1.6 $ $Date: 2004/03/15 14:45:06 $ + * @access public + * @see FilterReader + * @package phing.filters + */ +class HeadFilter extends BaseParamFilterReader implements ChainableReader { + + /** + * Parameter name for the number of lines to be returned. + */ + const LINES_KEY = "lines"; + + /** + * Number of lines currently read in. + * @var integer + */ + private $_linesRead = 0; + + /** + * Number of lines to be returned in the filtered stream. + * @var integer + */ + private $_lines = 10; + + /** + * Returns first n lines of stream. + * @return the resulting stream, or -1 + * if the end of the resulting stream has been reached + * + * @exception IOException if the underlying stream throws an IOException + * during reading + */ + function read($len = null) { + + if ( !$this->getInitialized() ) { + $this->_initialize(); + $this->setInitialized(true); + } + + // note, if buffer contains fewer lines than + // $this->_lines this code will not work. + + if($this->_linesRead < $this->_lines) { + + $buffer = $this->in->read($len); + + if($buffer === -1) { + return -1; + } + + // now grab first X lines from buffer + + $lines = explode("\n", $buffer); + + $linesCount = count($lines); + + // must account for possibility that the num lines requested could + // involve more than one buffer read. + $len = ($linesCount > $this->_lines ? $this->_lines - $this->_linesRead : $linesCount); + $filtered_buffer = implode("\n", array_slice($lines, 0, $len) ); + $this->_linesRead += $len; + + return $filtered_buffer; + + } + + return -1; // EOF, since the file is "finished" as far as subsequent filters are concerned. + } + + /** + * Sets the number of lines to be returned in the filtered stream. + * + * @param integer $lines the number of lines to be returned in the filtered stream. + */ + function setLines($lines) { + $this->_lines = (int) $lines; + } + + /** + * Returns the number of lines to be returned in the filtered stream. + * + * @return integer The number of lines to be returned in the filtered stream. + */ + function getLines() { + return $this->_lines; + } + + /** + * Creates a new HeadFilter using the passed in + * Reader for instantiation. + * + * @param object A Reader object providing the underlying stream. + * Must not be null. + * + * @return object A new filter based on this configuration, but filtering + * the specified reader. + */ + function chain(Reader $reader) { + $newFilter = new HeadFilter($reader); + $newFilter->setLines($this->getLines()); + $newFilter->setInitialized(true); + $newFilter->setProject($this->getProject()); + return $newFilter; + } + + /** + * Scans the parameters list for the "lines" parameter and uses + * it to set the number of lines to be returned in the filtered stream. + */ + private function _initialize() { + $params = $this->getParameters(); + if ( $params !== null ) { + for($i = 0, $_i=count($params) ; $i < $_i; $i++) { + if ( self::LINES_KEY == $params[$i]->getName() ) { + $this->_lines = (int) $params[$i]->getValue(); + break; + } + } + } + } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/LineContains.php b/buildscripts/phing/classes/phing/filters/LineContains.php new file mode 100644 index 00000000..8f3136b7 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/LineContains.php @@ -0,0 +1,258 @@ +. + */ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/filters/BaseFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Filter which includes only those lines that contain all the user-specified + * strings. + * + * Example: + * + *
                                                
                                                + *   
                                                + *   
                                                + * 
                                                + * + * Or: + * + *
                                                
                                                + *    
                                                + *    
                                                + * 
                                                + * + * This will include only those lines that contain foo and + * bar. + * + * @author Yannick Lecaillez + * @author Hans Lellelid + * @version $Revision: 1.11 $ + * @see PhingFilterReader + * @package phing.filters +*/ +class LineContains extends BaseParamFilterReader implements ChainableReader { + + /** + * The parameter name for the string to match on. + * @var string + */ + const CONTAINS_KEY = "contains"; + + /** + * Array of Contains objects. + * @var array + */ + private $_contains = array(); + + /** + * [Deprecated] + * @var string + */ + private $_line = null; + + /** + * Returns all lines in a buffer that contain specified strings. + * @return mixed buffer, -1 on EOF + */ + function read($len = null) { + if ( !$this->getInitialized() ) { + $this->_initialize(); + $this->setInitialized(true); + } + + $buffer = $this->in->read($len); + + if ($buffer === -1) { + return -1; + } + + $lines = explode("\n", $buffer); + $matched = array(); + $containsSize = count($this->_contains); + + foreach($lines as $line) { + for($i = 0 ; $i < $containsSize ; $i++) { + $containsStr = $this->_contains[$i]->getValue(); + if ( strstr($line, $containsStr) === false ) { + $line = null; + break; + } + } + if($line !== null) { + $matched[] = $line; + } + } + $filtered_buffer = implode("\n", $matched); + return $filtered_buffer; + } + + /** + * [Deprecated. For reference only, used to be read() method.] + * Returns the next character in the filtered stream, only including + * lines from the original stream which contain all of the specified words. + * + * @return the next character in the resulting stream, or -1 + * if the end of the resulting stream has been reached + * + * @exception IOException if the underlying stream throws an IOException + * during reading + */ + function readChar() { + if ( !$this->getInitialized() ) { + $this->_initialize(); + $this->setInitialized(true); + } + + $ch = -1; + + if ( $this->_line !== null ) { + $ch = substr($this->_line, 0, 1); + if ( strlen($this->_line) === 1 ) + $this->_line = null; + else + $this->_line = substr($this->_line, 1); + } else { + $this->_line = $this->readLine(); + if ( $this->_line === null ) { + $ch = -1; + } else { + $containsSize = count($this->_contains); + for($i = 0 ; $i < $containsSize ; $i++) { + $containsStr = $this->_contains[$i]->getValue(); + if ( strstr($this->_line, $containsStr) === false ) { + $this->_line = null; + break; + } + } + return $this->readChar(); + } + } + + return $ch; + } + + /** + * Adds a nested element. + * + * @return Contains The contains element added. + * Must not be null. + */ + function createContains() { + $num = array_push($this->_contains, new Contains()); + return $this->_contains[$num-1]; + } + + /** + * Sets the array of words which must be contained within a line read + * from the original stream in order for it to match this filter. + * + * @param array $contains An array of words which must be contained + * within a line in order for it to match in this filter. + * Must not be null. + */ + function setContains($contains) { + // type check, error must never occur, bad code of it does + if ( !is_array($contains) ) { + throw new Exception("Excpected array got something else"); + } + + $this->_contains = $contains; + } + + /** + * Returns the vector of words which must be contained within a line read + * from the original stream in order for it to match this filter. + * + * @return array The array of words which must be contained within a line read + * from the original stream in order for it to match this filter. The + * returned object is "live" - in other words, changes made to the + * returned object are mirrored in the filter. + */ + function getContains() { + return $this->_contains; + } + + /** + * Creates a new LineContains using the passed in + * Reader for instantiation. + * + * @param object A Reader object providing the underlying stream. + * Must not be null. + * + * @return object A new filter based on this configuration, but filtering + * the specified reader + */ + function chain(Reader $reader) { + $newFilter = new LineContains($reader); + $newFilter->setContains($this->getContains()); + $newFilter->setInitialized(true); + $newFilter->setProject($this->getProject()); + return $newFilter; + } + + /** + * Parses the parameters to add user-defined contains strings. + */ + private function _initialize() { + $params = $this->getParameters(); + if ( $params !== null ) { + foreach($params as $param) { + if ( self::CONTAINS_KEY == $param->getType() ) { + $cont = new Contains(); + $cont->setValue($param->getValue()); + array_push($this->_contains, $cont); + break; // because we only support a single contains + } + } + } + } +} + +/** + * Holds a contains element. + */ +class Contains { + + /** + * @var string + */ + private $_value; + + /** + * Set 'contains' value. + * @param string $contains + */ + function setValue($contains) { + $this->_value = (string) $contains; + } + + /** + * Returns 'contains' value. + * @return string + */ + function getValue() { + return $this->_value; + } +} +?> diff --git a/buildscripts/phing/classes/phing/filters/LineContainsRegexp.php b/buildscripts/phing/classes/phing/filters/LineContainsRegexp.php new file mode 100644 index 00000000..dcbb532c --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/LineContainsRegexp.php @@ -0,0 +1,179 @@ +. +*/ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/types/RegularExpression.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Filter which includes only those lines that contain the user-specified + * regular expression matching strings. + * + * Example: + *
                                                
                                                + *   
                                                + * 
                                                + * + * Or: + * + *
                                                
                                                + *    
                                                + * 
                                                + * + * This will fetch all those lines that contain the pattern foo + * + * @author Yannick Lecaillez + * @author Hans Lellelid + * @version $Revision: 1.8 $ + * @see FilterReader + * @package phing.filters + */ +class LineContainsRegexp extends BaseParamFilterReader implements ChainableReader { + + /** + * Parameter name for regular expression. + * @var string + */ + const REGEXP_KEY = "regexp"; + + /** + * Regular expressions that are applied against lines. + * @var array + */ + private $_regexps = array(); + + /** + * Returns all lines in a buffer that contain specified strings. + * @return mixed buffer, -1 on EOF + */ + function read($len = null) { + + if ( !$this->getInitialized() ) { + $this->_initialize(); + $this->setInitialized(true); + } + + $buffer = $this->in->read($len); + + if ($buffer === -1) { + return -1; + } + + $lines = explode("\n", $buffer); + $matched = array(); + + $regexpsSize = count($this->_regexps); + foreach($lines as $line) { + for($i = 0 ; $i<$regexpsSize ; $i++) { + $regexp = $this->_regexps[$i]; + $re = $regexp->getRegexp($this->getProject()); + $matches = $re->matches($line); + if ( !$matches ) { + $line = null; + break; + } + } + if($line !== null) { + $matched[] = $line; + } + } + $filtered_buffer = implode("\n", $matched); + return $filtered_buffer; + } + + /** + * Adds a regexp element. + * + * @return object regExp The regexp element added. + */ + function createRegexp() { + $num = array_push($this->_regexps, new RegularExpression()); + return $this->_regexps[$num-1]; + } + + /** + * Sets the vector of regular expressions which must be contained within + * a line read from the original stream in order for it to match this + * filter. + * + * @param regexps An array of regular expressions which must be contained + * within a line in order for it to match in this filter. Must not be + * null. + */ + function setRegexps($regexps) { + // type check, error must never occur, bad code of it does + if ( !is_array($regexps) ) { + throw new Exception("Excpected an 'array', got something else"); + } + $this->_regexps = $regexps; + } + + /** + * Returns the array of regular expressions which must be contained within + * a line read from the original stream in order for it to match this + * filter. + * + * @return array The array of regular expressions which must be contained within + * a line read from the original stream in order for it to match this + * filter. The returned object is "live" - in other words, changes made to + * the returned object are mirrored in the filter. + */ + function getRegexps() { + return $this->_regexps; + } + + /** + * Creates a new LineContainsRegExp using the passed in + * Reader for instantiation. + * + * @param object A Reader object providing the underlying stream. + * Must not be null. + * + * @return object A new filter based on this configuration, but filtering + * the specified reader + */ + function chain(Reader $reader) { + $newFilter = new LineContainsRegExp($reader); + $newFilter->setRegexps($this->getRegexps()); + $newFilter->setInitialized(true); + $newFilter->setProject($this->getProject()); + return $newFilter; + } + + /** + * Parses parameters to add user defined regular expressions. + */ + private function _initialize() { + $params = $this->getParameters(); + if ( $params !== null ) { + for($i = 0 ; $igetType() ) { + $pattern = $params[$i]->getValue(); + $regexp = new RegularExpression(); + $regexp->setPattern($pattern); + array_push($this->_regexps, $regexp); + } + } + } + } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/PrefixLines.php b/buildscripts/phing/classes/phing/filters/PrefixLines.php new file mode 100644 index 00000000..a5580f87 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/PrefixLines.php @@ -0,0 +1,142 @@ +. +*/ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Attaches a prefix to every line. + * + * Example: + *
                                                + * + * Or: + * + *
                                                
                                                + *  
                                                + * 
                                                + * + * @author Yannick Lecaillez + * @author hans lellelid, hans@velum.net + * @version $Revision: 1.6 $ $Date: 2004/03/15 14:45:06 $ + * @access public + * @see FilterReader + * @package phing.filters +*/ +class PrefixLines extends BaseParamFilterReader implements ChainableReader { + + /** + * Parameter name for the prefix. + * @var string + */ + const PREFIX_KEY = "lines"; + + /** + * The prefix to be used. + * @var string + */ + private $_prefix = null; + + /** + * Adds a prefix to each line of input stream and returns resulting stream. + * + * @return mixed buffer, -1 on EOF + */ + function read($len = null) { + if ( !$this->getInitialized() ) { + $this->_initialize(); + $this->setInitialized(true); + } + + $buffer = $this->in->read($len); + + if ($buffer === -1) { + return -1; + } + + $lines = explode("\n", $buffer); + $filtered = array(); + + foreach($lines as $line) { + $line = $this->_prefix . $line; + $filtered[] = $line; + } + + $filtered_buffer = implode("\n", $filtered); + return $filtered_buffer; + } + + /** + * Sets the prefix to add at the start of each input line. + * + * @param string $prefix The prefix to add at the start of each input line. + * May be null, in which case no prefix + * is added. + */ + function setPrefix($prefix) { + $this->_prefix = (string) $prefix; + } + + /** + * Returns the prefix which will be added at the start of each input line. + * + * @return string The prefix which will be added at the start of each input line + */ + function getPrefix() { + return $this->_prefix; + } + + /** + * Creates a new PrefixLines filter using the passed in + * Reader for instantiation. + * + * @param object A Reader object providing the underlying stream. + * Must not be null. + * + * @return object A new filter based on this configuration, but filtering + * the specified reader + */ + function chain(Reader $reader) { + $newFilter = new PrefixLines($reader); + $newFilter->setPrefix($this->getPrefix()); + $newFilter->setInitialized(true); + $newFilter->setProject($this->getProject()); + return $newFilter; + } + + /** + * Initializes the prefix if it is available from the parameters. + */ + private function _initialize() { + $params = $this->getParameters(); + if ( $params !== null ) { + for($i = 0, $_i=count($params) ; $i < $_i ; $i++) { + if ( self::PREFIX_KEY == $params[$i]->getName() ) { + $this->_prefix = (string) $params[$i]->getValue(); + break; + } + } + } + } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/ReplaceRegexp.php b/buildscripts/phing/classes/phing/filters/ReplaceRegexp.php new file mode 100644 index 00000000..3c5592e8 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/ReplaceRegexp.php @@ -0,0 +1,129 @@ +. +*/ + +require_once 'phing/filters/BaseFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; +include_once 'phing/types/RegularExpression.php'; + +/** + * Performs a regexp find/replace on stream. + *

                                                + * Example:
                                                + *

                                                + * 
                                                + *    
                                                + *    
                                                + * 
                                                + * 
                                                + * + * @author Hans Lellelid + * @version $Revision: 1.5 $ + * @package phing.filters + */ +class ReplaceRegexp extends BaseFilterReader implements ChainableReader { + + /** + * @var array RegularExpression[] + */ + private $regexps = array(); + + /** + * Creator method handles nested tags. + * @return RegularExpression + */ + function createRegexp() { + $num = array_push($this->regexps, new RegularExpression()); + return $this->regexps[$num-1]; + } + + /** + * Sets the current regexps. + * (Used when, e.g., cloning/chaining the method.) + * @param array RegularExpression[] + */ + function setRegexps($regexps) { + $this->regexps = $regexps; + } + + /** + * Gets the current regexps. + * (Used when, e.g., cloning/chaining the method.) + * @return array RegularExpression[] + */ + function getRegexps() { + return $this->regexps; + } + + /** + * Returns the filtered stream. + * The original stream is first read in fully, and the regex replace is performed. + * + * @param int $len Required $len for Reader compliance. + * + * @return mixed The filtered stream, or -1 if the end of the resulting stream has been reached. + * + * @exception IOException if the underlying stream throws an IOException + * during reading + */ + function read($len = null) { + + $buffer = $this->in->read($len); + + if($buffer === -1) { + return -1; + } + + // perform regex replace here ... + foreach($this->regexps as $exptype) { + $regexp = $exptype->getRegexp($this->project); + try { + $buffer = $regexp->replace($buffer); + $this->log("Performing regexp replace: /".$regexp->getPattern()."/".$regexp->getReplace()."/g".($regexp->getIgnoreCase() ? 'i' : ''), PROJECT_MSG_VERBOSE); + } catch (Exception $e) { + // perhaps mismatch in params (e.g. no replace or pattern specified) + $this->log("Error performing regexp replace: " . $e->getMessage(), PROJECT_MSG_WARN); + } + } + + return $buffer; + } + + /** + * Creates a new ReplaceRegExp filter using the passed in + * Reader for instantiation. + * + * @param Reader $reader A Reader object providing the underlying stream. + * Must not be null. + * + * @return ReplaceRegExp A new filter based on this configuration, but filtering + * the specified reader + */ + function chain(Reader $reader) { + $newFilter = new ReplaceRegExp($reader); + $newFilter->setProject($this->getProject()); + $newFilter->setRegexps($this->getRegexps()); + return $newFilter; + } + +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/ReplaceTokens.php b/buildscripts/phing/classes/phing/filters/ReplaceTokens.php new file mode 100644 index 00000000..999f734f --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/ReplaceTokens.php @@ -0,0 +1,415 @@ +. +*/ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/types/TokenSource.php'; +include_once 'phing/filters/ChainableReader.php'; + +/* + * Replaces tokens in the original input with user-supplied values. + * + * Example: + * + *
                                                ;
                                                + *   
                                                + * 
                                                + * + * Or: + * + *
                                                
                                                + *   
                                                + *   
                                                + *   
                                                + * 
                                                + * + * @author Yannick Lecaillez + * @author hans lellelid, hans@velum.net + * @version $Revision: 1.14 $ $Date: 2005/06/16 15:09:10 $ + * @access public + * @see BaseParamFilterReader + * @package phing.filters + */ +class ReplaceTokens extends BaseParamFilterReader implements ChainableReader { + + /** + * Default "begin token" character. + * @var string + */ + const DEFAULT_BEGIN_TOKEN = "@"; + + /** + * Default "end token" character. + * @var string + */ + const DEFAULT_END_TOKEN = "@"; + + /** + * [Deprecated] Data that must be read from, if not null. + * @var string + */ + private $_queuedData = null; + + /** + * Array to hold the replacee-replacer pairs (String to String). + * @var array + */ + private $_tokens = array(); + + /** + * Array to hold the token sources that make tokens from + * different sources available + * @var array + */ + private $_tokensources = array(); + + /** + * Array holding all tokens given directly to the Filter and + * those passed via a TokenSource. + * @var array + */ + private $_alltokens = null; + + /** + * Character marking the beginning of a token. + * @var string + */ + private $_beginToken = "@"; // self::DEFAULT_BEGIN_TOKEN; + + /** + * Character marking the end of a token. + * @var string + */ + private $_endToken = "@"; //self::DEFAULT_END_TOKEN; + + /** + * Performs lookup on key and returns appropriate replacement string. + * @param array $matches Array of 1 el containing key to search for. + * @return string Text with which to replace key or value of key if none is found. + * @access private + */ + private function replaceTokenCallback($matches) { + + $key = $matches[1]; + + /* Get tokens from tokensource and merge them with the + * tokens given directly via build file. This should be + * done a bit more elegantly + */ + if ($this->_alltokens === null) { + $this->_alltokens = array(); + + $count = count($this->_tokensources); + for ($i = 0; $i < $count; $i++) { + $source = $this->_tokensources[$i]; + $this->_alltokens = array_merge($this->_alltokens, $source->getTokens()); + } + + + $this->_alltokens = array_merge($this->_tokens, $this->_alltokens); + } + + $tokens = $this->_alltokens; + + $replaceWith = null; + $count = count($tokens); + + for ($i = 0; $i < $count; $i++) { + if ($tokens[$i]->getKey() === $key) { + $replaceWith = $tokens[$i]->getValue(); + } + } + + if ($replaceWith === null) { + $replaceWith = $this->_beginToken . $key . $this->_endToken; + $this->log("No token defined for key \"".$this->_beginToken . $key . $this->_endToken."\""); + } else { + $this->log("Replaced \"".$this->_beginToken . $key . $this->_endToken ."\" with \"".$replaceWith."\""); + } + + return $replaceWith; + } + + /** + * Returns stream with tokens having been replaced with appropriate values. + * If a replacement value is not found for a token, the token is left in the stream. + * + * @return mixed filtered stream, -1 on EOF. + */ + function read($len = null) { + if ( !$this->getInitialized() ) { + $this->_initialize(); + $this->setInitialized(true); + } + + // read from next filter up the chain + $buffer = $this->in->read($len); + + if($buffer === -1) { + return -1; + } + + // filter buffer + $buffer = preg_replace_callback( + "/".preg_quote($this->_beginToken)."([\w\.\-:]+?)".preg_quote($this->_endToken)."/", + array($this, 'replaceTokenCallback'), $buffer); + + return $buffer; + } + + /** + * Sets the "begin token" character. + * + * @param string $beginToken the character used to denote the beginning of a token. + */ + function setBeginToken($beginToken) { + $this->_beginToken = (string) $beginToken; + } + + /** + * Returns the "begin token" character. + * + * @return string The character used to denote the beginning of a token. + */ + function getBeginToken() { + return $this->_beginToken; + } + + /** + * Sets the "end token" character. + * + * @param string $endToken the character used to denote the end of a token + */ + function setEndToken($endToken) { + $this->_endToken = (string) $endToken; + } + + /** + * Returns the "end token" character. + * + * @return the character used to denote the beginning of a token + */ + function getEndToken() { + return $this->_endToken; + } + + /** + * Adds a token element to the map of tokens to replace. + * + * @return object The token added to the map of replacements. + * Must not be null. + */ + function createToken() { + $num = array_push($this->_tokens, new Token()); + return $this->_tokens[$num-1]; + } + + /** + * Adds a token source to the sources of this filter. + * + * @return object A Reference to the source just added. + */ + function createTokensource() { + $num = array_push($this->_tokensources, new TokenSource()); + return $this->_tokensources[$num-1]; + } + + /** + * Sets the map of tokens to replace. + * ; used by ReplaceTokens::chain() + * + * @param array A map (String->String) of token keys to replacement + * values. Must not be null. + */ + function setTokens($tokens) { + // type check, error must never occur, bad code of it does + if ( !is_array($tokens) ) { + throw new Exception("Excpected 'array', got something else"); + } + + $this->_tokens = $tokens; + } + + /** + * Returns the map of tokens which will be replaced. + * ; used by ReplaceTokens::chain() + * + * @return array A map (String->String) of token keys to replacement values. + */ + function getTokens() { + return $this->_tokens; + } + + /** + * Sets the tokensources to use; used by ReplaceTokens::chain() + * + * @param array An array of token sources. + */ + function setTokensources($sources) { + // type check + if ( !is_array($sources)) { + throw new Exception("Exspected 'array', got something else"); + } + $this->_tokensources = $sources; + } + + /** + * Returns the token sources used by this filter; used by ReplaceTokens::chain() + * + * @return array + */ + function getTokensources() { + return $this->_tokensources; + } + + /** + * Creates a new ReplaceTokens using the passed in + * Reader for instantiation. + * + * @param object A Reader object providing the underlying stream. + * Must not be null. + * + * @return object A new filter based on this configuration, but filtering + * the specified reader + */ + function chain(Reader $reader) { + $newFilter = new ReplaceTokens($reader); + $newFilter->setProject($this->getProject()); + $newFilter->setBeginToken($this->getBeginToken()); + $newFilter->setEndToken($this->getEndToken()); + $newFilter->setTokens($this->getTokens()); + $newFilter->setTokensources($this->getTokensources()); + $newFilter->setInitialized(true); + return $newFilter; + } + + /** + * Initializes tokens and loads the replacee-replacer hashtable. + * This method is only called when this filter is used through + * a tag in build file. + */ + private function _initialize() { + $params = $this->getParameters(); + if ( $params !== null ) { + for($i = 0 ; $igetType(); + if ( $type === "tokenchar" ) { + $name = $params[$i]->getName(); + if ( $name === "begintoken" ) { + $this->_beginToken = substr($params[$i]->getValue(), 0, 1); + } else if ( $name === "endtoken" ) { + $this->_endToken = substr($params[$i]->getValue(), 0, 1); + } + } else if ( $type === "token" ) { + $name = $params[$i]->getName(); + $value = $params[$i]->getValue(); + + $tok = new Token(); + $tok->setKey($name); + $tok->setValue($value); + + array_push($this->_tokens, $tok); + } else if ( $type === "tokensource" ) { + // Store data from nested tags in local array + $arr = array(); $subparams = $params[$i]->getParams(); + $count = count($subparams); + for ($i = 0; $i < $count; $i++) { + $arr[$subparams[$i]->getName()] = $subparams[$i]->getValue(); + } + + // Create TokenSource + $tokensource = new TokenSource(); + if (isset($arr["classname"])) + $tokensource->setClassname($arr["classname"]); + + // Copy other parameters 1:1 to freshly created TokenSource + foreach ($arr as $key => $value) { + if (strtolower($key) === "classname") + continue; + $param = $tokensource->createParam(); + $param->setName($key); + $param->setValue($value); + } + + $this->_tokensources[] = $tokensource; + } + } + } + } + } +} + +/** + * Holds a token. + */ +class Token { + + /** + * Token key. + * @var string + */ + private $_key; + + /** + * Token value. + * @var string + */ + private $_value; + + /** + * Sets the token key. + * + * @param string $key The key for this token. Must not be null. + */ + function setKey($key) { + $this->_key = (string) $key; + } + + /** + * Sets the token value. + * + * @param string $value The value for this token. Must not be null. + */ + function setValue($value) { + $this->_value = (string) $value; + } + + /** + * Returns the key for this token. + * + * @return string The key for this token. + */ + function getKey() { + return $this->_key; + } + + /** + * Returns the value for this token. + * + * @return string The value for this token. + */ + function getValue() { + return $this->_value; + } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/StripLineBreaks.php b/buildscripts/phing/classes/phing/filters/StripLineBreaks.php new file mode 100644 index 00000000..c5a06129 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/StripLineBreaks.php @@ -0,0 +1,148 @@ +. +*/ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Filter to flatten the stream to a single line. + * + * Example: + * + *
                                                + * + * Or: + * + *
                                                + * + * @author Yannick Lecaillez + * @author hans lellelid, hans@velum.net + * @version $Revision: 1.8 $ $Date: 2004/03/15 14:45:06 $ + * @access public + * @see BaseParamFilterReader + * @package phing.filters + */ +class StripLineBreaks extends BaseParamFilterReader implements ChainableReader { + + /** + * Default line-breaking characters. + * @var string + */ + const DEFAULT_LINE_BREAKS = "\r\n"; + + /** + * Parameter name for the line-breaking characters parameter. + * @var string + */ + const LINES_BREAKS_KEY = "linebreaks"; + + /** + * The characters that are recognized as line breaks. + * @var string + */ + private $_lineBreaks = "\r\n"; // self::DEFAULT_LINE_BREAKS; + + /** + * Returns the filtered stream, only including + * characters not in the set of line-breaking characters. + * + * @return mixed the resulting stream, or -1 + * if the end of the resulting stream has been reached. + * + * @exception IOException if the underlying stream throws an IOException + * during reading + */ + function read($len = null) { + if ( !$this->getInitialized() ) { + $this->_initialize(); + $this->setInitialized(true); + } + + $buffer = $this->in->read($len); + if($buffer === -1) { + return -1; + } + + $buffer = preg_replace("/[".$this->_lineBreaks."]/", '', $buffer); + + return $buffer; + } + + /** + * Sets the line-breaking characters. + * + * @param string $lineBreaks A String containing all the characters to be + * considered as line-breaking. + */ + function setLineBreaks($lineBreaks) { + $this->_lineBreaks = (string) $lineBreaks; + } + + /** + * Gets the line-breaking characters. + * + * @return string A String containing all the characters that are considered as line-breaking. + */ + function getLineBreaks() { + return $this->_lineBreaks; + } + + /** + * Creates a new StripLineBreaks using the passed in + * Reader for instantiation. + * + * @param object A Reader object providing the underlying stream. + * Must not be null. + * + * @return object A new filter based on this configuration, but filtering + * the specified reader + */ + function chain(Reader $reader) { + $newFilter = new StripLineBreaks($reader); + $newFilter->setLineBreaks($this->getLineBreaks()); + $newFilter->setInitialized(true); + $newFilter->setProject($this->getProject()); + return $newFilter; + } + + /** + * Parses the parameters to set the line-breaking characters. + */ + private function _initialize() { + $userDefinedLineBreaks = null; + $params = $this->getParameters(); + if ( $params !== null ) { + for($i = 0 ; $igetName() ) { + $userDefinedLineBreaks = $params[$i]->getValue(); + break; + } + } + } + + if ( $userDefinedLineBreaks !== null ) { + $this->_lineBreaks = $userDefinedLineBreaks; + } + } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/StripLineComments.php b/buildscripts/phing/classes/phing/filters/StripLineComments.php new file mode 100644 index 00000000..5d97979a --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/StripLineComments.php @@ -0,0 +1,205 @@ +. +*/ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/* + * This filter strips line comments. + * + * Example: + * + *
                                                
                                                + *   
                                                + *   
                                                + *   
                                                + *   
                                                + *   
                                                + * 
                                                + * + * Or: + * + *
                                                
                                                + *   
                                                + *   
                                                + *   
                                                + *   
                                                + *   
                                                + * 
                                                + * + * @author Yannick Lecaillez + * @author hans lellelid, hans@velum.net + * @version $Revision: 1.8 $ $Date: 2005/02/27 20:52:08 $ + * @access public + * @see BaseParamFilterReader + * @package phing.filters + */ +class StripLineComments extends BaseParamFilterReader implements ChainableReader { + + /** Parameter name for the comment prefix. */ + const COMMENTS_KEY = "comment"; + + /** Array that holds the comment prefixes. */ + private $_comments = array(); + + /** + * Returns stream only including + * lines from the original stream which don't start with any of the + * specified comment prefixes. + * + * @return mixed the resulting stream, or -1 + * if the end of the resulting stream has been reached. + * + * @throws IOException if the underlying stream throws an IOException + * during reading + */ + function read($len = null) { + + if ( !$this->getInitialized() ) { + $this->_initialize(); + $this->setInitialized(true); + } + + $buffer = $this->in->read($len); + + if ($buffer === -1) { + return -1; + } + + $lines = explode("\n", $buffer); + $filtered = array(); + + $commentsSize = count($this->_comments); + + foreach($lines as $line) { + for($i = 0; $i < $commentsSize; $i++) { + $comment = $this->_comments[$i]->getValue(); + if ( StringHelper::startsWith($comment, ltrim($line)) ) { + $line = null; + break; + } + } + if ($line !== null) { + $filtered[] = $line; + } + } + + $filtered_buffer = implode("\n", $filtered); + return $filtered_buffer; + } + + /* + * Adds a comment element to the list of prefixes. + * + * @return comment The comment element added to the + * list of comment prefixes to strip. + */ + function createComment() { + $num = array_push($this->_comments, new Comment()); + return $this->_comments[$num-1]; + } + + /* + * Sets the list of comment prefixes to strip. + * + * @param comments A list of strings, each of which is a prefix + * for a comment line. Must not be null. + */ + function setComments($lineBreaks) { + if (!is_array($lineBreaks)) { + throw new Exception("Excpected 'array', got something else"); + } + $this->_comments = $lineBreaks; + } + + /* + * Returns the list of comment prefixes to strip. + * + * @return array The list of comment prefixes to strip. + */ + function getComments() { + return $this->_comments; + } + + /* + * Creates a new StripLineComments using the passed in + * Reader for instantiation. + * + * @param reader A Reader object providing the underlying stream. + * Must not be null. + * + * @return a new filter based on this configuration, but filtering + * the specified reader + */ + function chain(Reader $reader) { + $newFilter = new StripLineComments($reader); + $newFilter->setComments($this->getComments()); + $newFilter->setInitialized(true); + $newFilter->setProject($this->getProject()); + return $newFilter; + } + + /* + * Parses the parameters to set the comment prefixes. + */ + private function _initialize() { + $params = $this->getParameters(); + if ( $params !== null ) { + for($i = 0 ; $igetType() ) { + $comment = new Comment(); + $comment->setValue($params[$i]->getValue()); + array_push($this->_comments, $comment); + } + } + } + } +} + +/* + * The class that holds a comment representation. +*/ +class Comment { + + /** The prefix for a line comment. */ + private $_value; + + /* + * Sets the prefix for this type of line comment. + * + * @param string $value The prefix for a line comment of this type. + * Must not be null. + */ + function setValue($value) { + $this->_value = (string) $value; + } + + /* + * Returns the prefix for this type of line comment. + * + * @return string The prefix for this type of line comment. + */ + function getValue() { + return $this->_value; + } +} +?> diff --git a/buildscripts/phing/classes/phing/filters/StripPhpComments.php b/buildscripts/phing/classes/phing/filters/StripPhpComments.php new file mode 100644 index 00000000..9e21eed3 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/StripPhpComments.php @@ -0,0 +1,190 @@ +. +*/ + +include_once 'phing/filters/BaseFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * This is a Php comment and string stripper reader that filters + * those lexical tokens out for purposes of simple Php parsing. + * (if you have more complex Php parsing needs, use a real lexer). + * Since this class heavily relies on the single char read function, + * you are reccomended to make it work on top of a buffered reader. + * + * @author Yannick Lecaillez + * @author hans lellelid, hans@velum.net + * @version $Revision: 1.6 $ $Date: 2004/07/16 01:36:35 $ + * @access public + * @see FilterReader + * @package phing.filters + * @todo -c use new PHP functions to perform this instead of regex. + */ +class StripPhpComments extends BaseFilterReader implements ChainableReader { + /** + * The read-ahead character, used for effectively pushing a single + * character back. -1 indicates that no character is in the buffer. + */ + private $_readAheadCh = -1; + + /** + * Whether or not the parser is currently in the middle of a string + * literal. + * @var boolean + */ + private $_inString = false; + + /** + * Returns the stream without Php comments. + * + * @return the resulting stream, or -1 + * if the end of the resulting stream has been reached + * + * @throws IOException if the underlying stream throws an IOException + * during reading + */ + function read($len = null) { + + $buffer = $this->in->read($len); + if($buffer === -1) { + return -1; + } + + // This regex replace /* */ and // style comments + $buffer = preg_replace('/\/\*[^*]*\*+([^\/*][^*]*\*+)*\/|\/\/[^\n]*|("(\\\\.|[^"\\\\])*"|\'(\\\\.|[^\'\\\\])*\'|.[^\/"\'\\\\]*)/s', "$2", $buffer); + + // The regex above is not identical to, but is based on the expression below: + // + // created by Jeffrey Friedl + // and later modified by Fred Curtis. + // s{ + // /\* ## Start of /* ... */ comment + // [^*]*\*+ ## Non-* followed by 1-or-more *'s + // ( + // [^/*][^*]*\*+ + // )* ## 0-or-more things which don't start with / + // ## but do end with '*' + // / ## End of /* ... */ comment + // + // | ## OR various things which aren't comments: + // + // ( + // " ## Start of " ... " string + // ( + // \\. ## Escaped char + // | ## OR + // [^"\\] ## Non "\ + // )* + // " ## End of " ... " string + // + // | ## OR + // + // ' ## Start of ' ... ' string + // ( + // \\. ## Escaped char + // | ## OR + // [^'\\] ## Non '\ + // )* + // ' ## End of ' ... ' string + // + // | ## OR + // + // . ## Anything other char + // [^/"'\\]* ## Chars which doesn't start a comment, string or escape + // ) + // }{$2}gxs; + + return $buffer; + } + + + /* + * Returns the next character in the filtered stream, not including + * Php comments. + * + * @return the next character in the resulting stream, or -1 + * if the end of the resulting stream has been reached + * + * @throws IOException if the underlying stream throws an IOException + * during reading + * @deprecated + */ + function readChar() { + $ch = -1; + + if ( $this->_readAheadCh !== -1 ) { + $ch = $this->_readAheadCh; + $this->_readAheadCh = -1; + } else { + $ch = $this->in->readChar(); + if ( $ch === "\"" ) { + $this->_inString = !$this->_inString; + } else { + if ( !$this->_inString ) { + if ( $ch === "/" ) { + $ch = $this->in->readChar(); + if ( $ch === "/" ) { + while ( $ch !== "\n" && $ch !== -1 ) { + $ch = $this->in->readChar(); + } + } else if ( $ch === "*" ) { + while ( $ch !== -1 ) { + $ch = $this->in->readChar(); + while ( $ch === "*" && $ch !== -1 ) { + $ch = $this->in->readChar(); + } + + if ( $ch === "/" ) { + $ch = $this->readChar(); + echo "$ch\n"; + break; + } + } + } else { + $this->_readAheadCh = $ch; + $ch = "/"; + } + } + } + } + } + + return $ch; + } + + /** + * Creates a new StripJavaComments using the passed in + * Reader for instantiation. + * + * @param reader A Reader object providing the underlying stream. + * Must not be null. + * + * @return a new filter based on this configuration, but filtering + * the specified reader + */ + function chain(Reader $reader) { + $newFilter = new StripPhpComments($reader); + $newFilter->setProject($this->getProject()); + return $newFilter; + } +} + +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/filters/TabToSpaces.php b/buildscripts/phing/classes/phing/filters/TabToSpaces.php new file mode 100644 index 00000000..7293d3b5 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/TabToSpaces.php @@ -0,0 +1,144 @@ +. +*/ + +require_once 'phing/filters/BaseParamFilterReader.php'; +require_once 'phing/filters/ChainableReader.php'; + +/** + * Converts tabs to spaces. + * + * Example: + * + *
                                                + * + * Or: + * + *
                                                
                                                + *   
                                                + * 
                                                + * + * @author Yannick Lecaillez + * @author Hans Lellelid + * @version $Revision: 1.9 $ + * @see BaseParamFilterReader + * @package phing.filters + */ +class TabToSpaces extends BaseParamFilterReader implements ChainableReader { + + /** + * The default tab length. + * @var int + */ + const DEFAULT_TAB_LENGTH = 8; + + /** + * Parameter name for the length of a tab. + * @var string + */ + const TAB_LENGTH_KEY = "tablength"; + + /** + * Tab length in this filter. + * @var int + */ + private $tabLength = 8; //self::DEFAULT_TAB_LENGTH; + + /** + * Returns stream after converting tabs to the specified number of spaces. + * + * @return the resulting stream, or -1 + * if the end of the resulting stream has been reached + * + * @exception IOException if the underlying stream throws an IOException + * during reading + */ + function read($len = null) { + + if ( !$this->getInitialized() ) { + $this->_initialize(); + $this->setInitialized(true); + } + + $buffer = $this->in->read($len); + + if($buffer === -1) { + return -1; + } + + $buffer = str_replace("\t", str_repeat(' ', $this->tabLength), $buffer); + + return $buffer; + } + + /** + * Sets the tab length. + * + * @param int $tabLength The number of spaces to be used when converting a tab. + */ + function setTablength($tabLength) { + $this->tabLength = (int) $tabLength; + } + + /** + * Returns the tab length. + * + * @return int The number of spaces used when converting a tab + */ + function getTablength() { + return $this->tabLength; + } + + /** + * Creates a new TabsToSpaces using the passed in + * Reader for instantiation. + * + * @param Reader $reader A Reader object providing the underlying stream. + * Must not be null. + * + * @return Reader A new filter based on this configuration, but filtering + * the specified reader + */ + function chain(Reader $reader) { + $newFilter = new TabToSpaces($reader); + $newFilter->setTablength($this->getTablength()); + $newFilter->setInitialized(true); + $newFilter->setProject($this->getProject()); + return $newFilter; + } + + /** + * Parses the parameters to set the tab length. + */ + private function _initialize() { + $params = $this->getParameters(); + if ( $params !== null ) { + for($i = 0 ; $igetName()) { + $this->tabLength = $params[$i]->getValue(); + break; + } + } + } + } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/TailFilter.php b/buildscripts/phing/classes/phing/filters/TailFilter.php new file mode 100644 index 00000000..a6af6e4b --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/TailFilter.php @@ -0,0 +1,157 @@ +. +*/ + +require_once 'phing/filters/BaseParamFilterReader.php'; + +/** + * Reads the last n lines of a stream. (Default is last10 lines.) + * + * Example: + * + *
                                                + * + * Or: + * + *
                                                
                                                + *   
                                                + * 
                                                + * + * @author Yannick Lecaillez + * @author hans lellelid, hans@velum.net + * @copyright © 2003 seasonfive. All rights reserved + * @version $Revision: 1.7 $ + * @see BaseParamFilterReader + * @package phing.filters + */ +class TailFilter extends BaseParamFilterReader implements ChainableReader { + + /** + * Parameter name for the number of lines to be returned. + * @var string + */ + const LINES_KEY = "lines"; + + + /** + * Number of lines to be returned in the filtered stream. + * @var integer + */ + private $_lines = 10; + + /** + * Array to hold lines. + * @var array + */ + private $_lineBuffer = array(); + + /** + * Returns the last n lines of a file. + * @param int $len Num chars to read. + * @return mixed The filtered buffer or -1 if EOF. + */ + function read($len = null) { + + while ( ($buffer = $this->in->read($len)) !== -1 ) { + // Remove the last "\n" from buffer for + // prevent explode to add an empty cell at + // the end of array + $buffer= trim($buffer, "\n"); + + $lines = explode("\n", $buffer); + + if ( count($lines) >= $this->_lines ) { + // Buffer have more (or same) number of lines than needed. + // Fill lineBuffer with the last "$this->_lines" lasts ones. + $off = count($lines)-$this->_lines; + $this->_lineBuffer = array_slice($lines, $off); + } else { + // Some new lines ... + // Prepare space for insert these new ones + $this->_lineBuffer = array_slice($this->_lineBuffer, count($lines)-1); + $this->_lineBuffer = array_merge($this->_lineBuffer, $lines); + } + } + + if ( empty($this->_lineBuffer) ) + $ret = -1; + else { + $ret = implode("\n", $this->_lineBuffer); + $this->_lineBuffer = array(); + } + + return $ret; + } + + /** + * Sets the number of lines to be returned in the filtered stream. + * + * @param integer $lines the number of lines to be returned in the filtered stream. + */ + function setLines($lines) { + $this->_lines = (int) $lines; + } + + /** + * Returns the number of lines to be returned in the filtered stream. + * + * @return integer The number of lines to be returned in the filtered stream. + */ + function getLines() { + return $this->_lines; + } + + /** + * Creates a new TailFilter using the passed in + * Reader for instantiation. + * + * @param object A Reader object providing the underlying stream. + * Must not be null. + * + * @return object A new filter based on this configuration, but filtering + * the specified reader. + */ + function chain(Reader $reader) { + $newFilter = new TailFilter($reader); + $newFilter->setLines($this->getLines()); + $newFilter->setInitialized(true); + $newFilter->setProject($this->getProject()); + return $newFilter; + } + + /** + * Scans the parameters list for the "lines" parameter and uses + * it to set the number of lines to be returned in the filtered stream. + */ + private function _initialize() { + $params = $this->getParameters(); + if ( $params !== null ) { + for($i=0, $_i=count($params); $i < $_i; $i++) { + if ( self::LINES_KEY == $params[$i]->getName() ) { + $this->_lines = (int) $params[$i]->getValue(); + break; + } + } + } + } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/TidyFilter.php b/buildscripts/phing/classes/phing/filters/TidyFilter.php new file mode 100644 index 00000000..10d75fc4 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/TidyFilter.php @@ -0,0 +1,162 @@ +. +*/ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * This filter uses the bundled-with-PHP Tidy extension to filter input. + * + *

                                                + * Example:
                                                + *

                                                + * 
                                                + *   
                                                + *   
                                                + * 
                                                + * 
                                                + * + * @author Hans Lellelid + * @version $Revision: 1.2 $ $Date: 2005/12/08 19:15:20 $ + * @package phing.filters + */ +class TidyFilter extends BaseParamFilterReader implements ChainableReader { + + /** @var string Encoding of resulting document. */ + private $encoding = 'utf8'; + + /** @var array Parameter[] */ + private $configParameters = array(); + + /** + * Set the encoding for resulting (X)HTML document. + * @param string $v + */ + public function setEncoding($v) { + $this->encoding = $v; + } + + /** + * Sets the config params. + * @param array Parameter[] + * @see chain() + */ + public function setConfigParameters($params) + { + $this->configParameters = $params; + } + + /** + * Adds a element (which is a Parameter). + * @return Parameter + */ + public function createConfig() { + $num = array_push($this->configParameters, new Parameter()); + return $this->configParameters[$num-1]; + } + + /** + * Converts the Parameter objects being used to store configuration into a simle assoc array. + * @return array + */ + private function getDistilledConfig() { + $config = array(); + foreach($this->configParameters as $p) { + $config[$p->getName()] = $p->getValue(); + } + return $config; + } + + /** + * Reads input and returns Tidy-filtered output. + * + * @return the resulting stream, or -1 if the end of the resulting stream has been reached + * + * @throws IOException if the underlying stream throws an IOException + * during reading + */ + function read($len = null) { + + if (!class_exists('Tidy')) { + throw new BuildException("You must enable the 'tidy' extension in your PHP configuration in order to use the Tidy filter."); + } + + if ( !$this->getInitialized() ) { + $this->_initialize(); + $this->setInitialized(true); + } + + $buffer = $this->in->read($len); + if($buffer === -1) { + return -1; + } + + $config = $this->getDistilledConfig(); + + $tidy = new Tidy(); + $tidy->parseString($buffer, $config, $this->encoding); + $tidy->cleanRepair(); + + return tidy_get_output($tidy); + + } + + + /** + * Creates a new TidyFilter using the passed in Reader for instantiation. + * + * @param reader A Reader object providing the underlying stream. + * Must not be null. + * + * @return a new filter based on this configuration, but filtering + * the specified reader + */ + public function chain(Reader $reader) { + $newFilter = new TidyFilter($reader); + $newFilter->setConfigParameters($this->configParameters); + $newFilter->setEncoding($this->encoding); + $newFilter->setProject($this->getProject()); + return $newFilter; + } + + /** + * Initializes any parameters (e.g. config options). + * This method is only called when this filter is used through a tag in build file. + */ + private function _initialize() { + $params = $this->getParameters(); + if ($params) { + foreach($params as $param) { + if ($param->getType() == "config") { + $this->configParameters[] = $param; + } else { + + if ($param->getName() == "encoding") { + $this->setEncoding($param->getValue()); + } + + } + + } + } + } + +} diff --git a/buildscripts/phing/classes/phing/filters/TranslateGettext.php b/buildscripts/phing/classes/phing/filters/TranslateGettext.php new file mode 100644 index 00000000..f71823e3 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/TranslateGettext.php @@ -0,0 +1,285 @@ +. +*/ + +require_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Replaces gettext("message id") and _("message id") with the translated string. + * + * Gettext is great for creating multi-lingual sites, but in some cases (e.g. for + * performance reasons) you may wish to replace the gettext calls with the translations + * of the strings; that's what this task is for. Note that this is similar to + * ReplaceTokens, but both the find and the replace aspect is more complicated -- hence + * this is a separate, stand-alone filter. + * + *

                                                + * Example:
                                                + *

                                                + * 
                                                + * 
                                                + * + * @author Hans Lellelid + * @version $Revision: 1.11 $ $Date: 2005/12/08 15:59:56 $ + * @access public + * @see BaseFilterReader + * @package phing.filters + */ +class TranslateGettext extends BaseParamFilterReader implements ChainableReader { + + // constants for specifying keys to expect + // when this is called using + const DOMAIN_KEY = "domain"; + const DIR_KEY = "dir"; + const LOCALE_KEY = "locale"; + + /** The domain to use */ + private $domain = 'messages'; + + /** The dir containing LC_MESSAGES */ + private $dir; + + /** The locale to use */ + private $locale; + + /** The system locale before it was changed for this filter. */ + private $storedLocale; + + /** + * Set the text domain to use. + * The text domain must correspond to the name of the compiled .mo files. + * E.g. "messages" ==> $dir/LC_MESSAGES/messages.mo + * "mydomain" ==> $dir/LC_MESSAGES/mydomain.mo + * @param string $domain + */ + function setDomain($domain) { + $this->domain = $domain; + } + + /** + * Get the current domain. + * @return string + */ + function getDomain() { + return $this->domain; + } + + /** + * Sets the root locale directory. + * @param PhingFile $dir + */ + function setDir(PhingFile $dir) { + $this->dir = $dir; + } + + /** + * Gets the root locale directory. + * @return PhingFile + */ + function getDir() { + return $this->dir; + } + + /** + * Sets the locale to use for translation. + * Note that for gettext() to work, you have to make sure this locale + * is specific enough for your system (e.g. some systems may allow an 'en' locale, + * but others will require 'en_US', etc.). + * @param string $locale + */ + function setLocale($locale) { + $this->locale = $locale; + } + + /** + * Gets the locale to use for translation. + * @return string + */ + function getLocale() { + return $this->locale; + } + + /** + * Make sure that required attributes are set. + * @throws BuldException - if any required attribs aren't set. + */ + protected function checkAttributes() { + if (!$this->domain || !$this->locale || !$this->dir) { + throw new BuildException("You must specify values for domain, locale, and dir attributes."); + } + } + + /** + * Initialize the gettext/locale environment. + * This method will change some env vars and locale settings; the + * restoreEnvironment should put them all back :) + * + * @return void + * @throws BuildException - if locale cannot be set. + * @see restoreEnvironment() + */ + protected function initEnvironment() { + $this->storedLocale = getenv("LANG"); + + $this->log("Setting locale to " . $this->locale, PROJECT_MSG_DEBUG); + putenv("LANG=".$this->locale); + $ret = setlocale(LC_ALL, $this->locale); + if ($ret === false) { + $msg = "Could not set locale to " . $this->locale + . ". You may need to use fully qualified name" + . " (e.g. en_US instead of en)."; + throw new BuildException($msg); + } + + $this->log("Binding domain '".$this->domain."' to " . $this->dir, PROJECT_MSG_DEBUG); + bindtextdomain($this->domain, $this->dir->getAbsolutePath()); + textdomain($this->domain); + } + + /** + * Restores environment settings and locale. + * This does _not_ restore any gettext-specific settings + * (e.g. textdomain()). + * + * @return void + */ + protected function restoreEnvironment() { + putenv("LANG=".$this->storedLocale); + setlocale(LC_ALL, $this->storedLocale); + } + + /** + * Performs gettext translation of msgid and returns translated text. + * + * This function simply wraps gettext() call, but provides ability to log + * string replacements. (alternative would be using preg_replace with /e which + * would probably be faster, but no ability to debug/log.) + * + * @param array $matches Array of matches; we're interested in $matches[2]. + * @return string Translated text + */ + private function xlateStringCallback($matches) { + $charbefore = $matches[1]; + $msgid = $matches[2]; + $translated = gettext($msgid); + $this->log("Translating \"$msgid\" => \"$translated\"", PROJECT_MSG_DEBUG); + return $charbefore . '"' . $translated . '"'; + } + + /** + * Returns the filtered stream. + * The original stream is first read in fully, and then translation is performed. + * + * @return mixed the filtered stream, or -1 if the end of the resulting stream has been reached. + * + * @throws IOException - if the underlying stream throws an IOException during reading + * @throws BuildException - if the correct params are not supplied + */ + function read($len = null) { + + if ( !$this->getInitialized() ) { + $this->_initialize(); + $this->setInitialized(true); + } + + // Make sure correct params/attribs have been set + $this->checkAttributes(); + + $buffer = $this->in->read($len); + if($buffer === -1) { + return -1; + } + + // Setup the locale/gettext environment + $this->initEnvironment(); + + + // replace any occurrences of _("") or gettext("") with + // the translated value. + // + // ([^\w]|^)_\("((\\"|[^"])*)"\) + // --$1--- -----$2---- + // ---$3-- [match escaped quotes or any char that's not a quote] + // + // also match gettext() -- same as above + + $buffer = preg_replace_callback('/([^\w]|^)_\("((\\\"|[^"])*)"\)/', array($this, 'xlateStringCallback'), $buffer); + $buffer = preg_replace_callback('/([^\w]|^)gettext\("((\\\"|[^"])*)"\)/', array($this, 'xlateStringCallback'), $buffer); + + // Check to see if there are any _('') calls and flag an error + + // Check to see if there are any unmatched gettext() calls -- and flag an error + + $matches = array(); + if (preg_match('/([^\w]|^)(gettext\([^\)]+\))/', $buffer, $matches)) { + $this->log("Unable to perform translation on: " . $matches[2], PROJECT_MSG_WARN); + } + + $this->restoreEnvironment(); + + return $buffer; + } + + /** + * Creates a new TranslateGettext filter using the passed in + * Reader for instantiation. + * + * @param Reader $reader A Reader object providing the underlying stream. + * Must not be null. + * + * @return TranslateGettext A new filter based on this configuration, but filtering + * the specified reader + */ + function chain(Reader $reader) { + $newFilter = new TranslateGettext($reader); + $newFilter->setProject($this->getProject()); + $newFilter->setDomain($this->getDomain()); + $newFilter->setLocale($this->getLocale()); + $newFilter->setDir($this->getDir()); + return $newFilter; + } + + /** + * Parses the parameters if this filter is being used in "generic" mode. + */ + private function _initialize() { + $params = $this->getParameters(); + if ( $params !== null ) { + foreach($params as $param) { + switch($param->getType()) { + case self::DOMAIN_KEY: + $this->setDomain($param->getValue()); + break; + case self::DIR_KEY: + $this->setDir($this->project->resolveFile($param->getValue())); + break; + + case self::LOCALE_KEY: + $this->setLocale($param->getValue()); + break; + } // switch + } + } // if params !== null + } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/XsltFilter.php b/buildscripts/phing/classes/phing/filters/XsltFilter.php new file mode 100644 index 00000000..0b8c4e6f --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/XsltFilter.php @@ -0,0 +1,317 @@ +. +*/ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Applies XSL stylesheet to incoming text. + * + * Uses PHP XSLT support (libxslt). + * + * @author Hans Lellelid + * @author Yannick Lecaillez + * @author Andreas Aderhold + * @version $Revision: 1.16 $ + * @see FilterReader + * @package phing.filters + */ +class XsltFilter extends BaseParamFilterReader implements ChainableReader { + + /** + * Path to XSL stylesheet. + * @var string + */ + private $xslFile = null; + + /** + * Whether XML file has been transformed. + * @var boolean + */ + private $processed = false; + + /** + * XSLT Params. + * @var array + */ + private $xsltParams = array(); + + /** + * Whether to use loadHTML() to parse the input XML file. + */ + private $html = false; + + /** + * Create new XSLT Param object, to handle the nested element. + * @return XSLTParam + */ + function createParam() { + $num = array_push($this->xsltParams, new XSLTParam()); + return $this->xsltParams[$num-1]; + } + + /** + * Sets the XSLT params for this class. + * This is used to "clone" this class, in the chain() method. + * @param array $params + */ + function setParams($params) { + $this->xsltParams = $params; + } + + /** + * Returns the XSLT params set for this class. + * This is used to "clone" this class, in the chain() method. + * @return array + */ + function getParams() { + return $this->xsltParams; + } + + /** + * Set the XSLT stylesheet. + * @param mixed $file PhingFile object or path. + */ + function setStyle(PhingFile $file) { + $this->xslFile = $file; + } + + /** + * Whether to use HTML parser for the XML. + * This is supported in libxml2 -- Yay! + * @return boolean + */ + function getHtml() { + return $this->html; + } + + /** + * Whether to use HTML parser for XML. + * @param boolean $b + */ + function setHtml($b) { + $this->html = (boolean) $b; + } + + /** + * Get the path to XSLT stylesheet. + * @return mixed XSLT stylesheet path. + */ + function getStyle() { + return $this->xslFile; + } + + /** + * Reads stream, applies XSLT and returns resulting stream. + * @return string transformed buffer. + * @throws BuildException - if XSLT support missing, if error in xslt processing + */ + function read($len = null) { + + if (!class_exists('XSLTProcessor')) { + throw new BuildException("Could not find the XSLTProcessor class. Make sure PHP has been compiled/configured to support XSLT."); + } + + if ($this->processed === true) { + return -1; // EOF + } + + if ( !$this->getInitialized() ) { + $this->_initialize(); + $this->setInitialized(true); + } + + // Read XML + $_xml = null; + while ( ($data = $this->in->read($len)) !== -1 ) + $_xml .= $data; + + if ($_xml === null ) { // EOF? + return -1; + } + + if(empty($_xml)) { + $this->log("XML file is empty!", PROJECT_MSG_WARN); + return ''; // return empty string, don't attempt to apply XSLT + } + + // Read XSLT + $_xsl = null; + $xslFr = new FileReader($this->xslFile); + $xslFr->readInto($_xsl); + + $this->log("Tranforming XML " . $this->in->getResource() . " using style " . $this->xslFile->getPath(), PROJECT_MSG_VERBOSE); + + $out = ''; + try { + $out = $this->process($_xml, $_xsl); + $this->processed = true; + } catch (IOException $e) { + throw new BuildException($e); + } + + return $out; + } + + // {{{ method _ProcessXsltTransformation($xml, $xslt) throws BuildException + /** + * Try to process the XSLT transformation + * + * @param string XML to process. + * @param string XSLT sheet to use for the processing. + * + * @throws BuildException On XSLT errors + */ + protected function process($xml, $xsl) { + + $processor = new XSLTProcessor(); + + $xmlDom = new DOMDocument(); + $xslDom = new DOMDocument(); + + if ($this->html) { + $xmlDom->loadHTML($xml); + } else { + $xmlDom->loadXML($xml); + } + + $xslDom->loadxml($xsl); + + $processor->importStylesheet($xslDom); + + // ignoring param "type" attrib, because + // we're only supporting direct XSL params right now + foreach($this->xsltParams as $param) { + $this->log("Setting XSLT param: " . $param->getName() . "=>" . $param->getExpression(), PROJECT_MSG_DEBUG); + $processor->setParameter(null, $param->getName(), $param->getExpression()); + } + + $result = $processor->transformToXML($xmlDom); + + if ( !$result ) { + //$errno = xslt_errno($processor); + //$err = xslt_error($processor); + throw new BuildException("XSLT Error"); + } else { + return $result; + } + } + + /** + * Creates a new XsltFilter using the passed in + * Reader for instantiation. + * + * @param Reader A Reader object providing the underlying stream. + * Must not be null. + * + * @return Reader A new filter based on this configuration, but filtering + * the specified reader + */ + function chain(Reader $reader) { + $newFilter = new XsltFilter($reader); + $newFilter->setProject($this->getProject()); + $newFilter->setStyle($this->getStyle()); + $newFilter->setInitialized(true); + $newFilter->setParams($this->getParams()); + $newFilter->setHtml($this->getHtml()); + return $newFilter; + } + + /** + * Parses the parameters to get stylesheet path. + */ + private function _initialize() { + $params = $this->getParameters(); + if ( $params !== null ) { + for($i = 0, $_i=count($params) ; $i < $_i; $i++) { + if ( $params[$i]->getType() === null ) { + if ($params[$i]->getName() === "style") { + $this->setStyle($params[$i]->getValue()); + } + } elseif ($params[$i]->getType() == "param") { + $xp = new XSLTParam(); + $xp->setName($params[$i]->getName()); + $xp->setExpression($params[$i]->getValue()); + $this->xsltParams[] = $xp; + } + } + } + } + +} + + +/** + * Class that holds an XSLT parameter. + */ +class XSLTParam { + + private $name; + + private $expr; + + /** + * Sets param name. + * @param string $name + */ + public function setName($name) { + $this->name = $name; + } + + /** + * Get param name. + * @return string + */ + public function getName() { + return $this->name; + } + + /** + * Sets expression value. + * @param string $expr + */ + public function setExpression($expr) { + $this->expr = $expr; + } + + /** + * Sets expression to dynamic register slot. + * @param RegisterSlot $expr + */ + public function setListeningExpression(RegisterSlot $expr) { + $this->expr = $expr; + } + + /** + * Returns expression value -- performs lookup if expr is registerslot. + * @return string + */ + public function getExpression() { + if ($this->expr instanceof RegisterSlot) { + return $this->expr->getValue(); + } else { + return $this->expr; + } + } +} + +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/filters/util/ChainReaderHelper.php b/buildscripts/phing/classes/phing/filters/util/ChainReaderHelper.php new file mode 100644 index 00000000..80508a82 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/util/ChainReaderHelper.php @@ -0,0 +1,184 @@ +. +*/ + +include_once 'phing/Project.php'; +include_once 'phing/filters/BaseFilterReader.php'; +include_once 'phing/types/PhingFilterReader.php'; +include_once 'phing/types/FilterChain.php'; +include_once 'phing/types/Parameter.php'; +include_once 'phing/util/FileUtils.php'; +include_once 'phing/util/StringHelper.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Process a FilterReader chain. + * + * Here, the interesting method is 'getAssembledReader'. + * The purpose of this one is to create a simple Reader object which + * apply all filters on another primary Reader object. + * + * For example : In copyFile (phing.util.FileUtils) the primary Reader + * is a FileReader object (more accuratly, a BufferedReader) previously + * setted for the source file to copy. So, consider this filterchain : + * + * + * + * + * + * + * + * + * + * getAssembledReader will return a Reader object wich read on each + * of these filters. Something like this : ('->' = 'which read data from') : + * + * [TABTOSPACES] -> [LINECONTAINS] -> [STRIPPHPCOMMENTS] -> [FILEREADER] + * (primary reader) + * + * So, getAssembledReader will return the TABTOSPACES Reader object. Then + * each read done with this Reader object will follow this path. + * + * Hope this explanation is clear :) + * + * TODO: Implement the classPath feature. + * + * @author Yannick Lecaillez + * @version $Revision: 1.8 $ $Date: 2005/02/27 20:52:09 $ + * @access public + * @package phing.filters.util +*/ +class ChainReaderHelper { + + /** Primary reader to wich the reader chain is to be attached */ + private $primaryReader = null; + + /** The site of the buffer to be used. */ + private $bufferSize = 8192; + + /** Chain of filters */ + private $filterChains = array(); + + /** The Phing project */ + private $project; + + /* + * Sets the primary reader + */ + function setPrimaryReader(Reader $reader) { + $this->primaryReader = $reader; + } + + /* + * Set the project to work with + */ + function setProject(Project $project) { + $this->project = $project; + } + + /* + * Get the project + */ + function getProject() { + return $this->project; + } + + /* + * Sets the buffer size to be used. Defaults to 8192, + * if this method is not invoked. + */ + function setBufferSize($size) { + $this->bufferSize = $size; + } + + /* + * Sets the collection of filter reader sets + */ + function setFilterChains(&$fchain) { + $this->filterChains = &$fchain; + } + + /* + * Assemble the reader + */ + function getAssembledReader() { + + $instream = $this->primaryReader; + $filterReadersCount = count($this->filterChains); + $finalFilters = array(); + + // Collect all filter readers of all filter chains used ... + for($i = 0 ; $i<$filterReadersCount ; $i++) { + $filterchain = &$this->filterChains[$i]; + $filterReaders = $filterchain->getFilterReaders(); + $readerCount = count($filterReaders); + for($j = 0 ; $j<$readerCount ; $j++) { + $finalFilters[] = $filterReaders[$j]; + } + } + + // ... then chain the filter readers. + $filtersCount = count($finalFilters); + if ( $filtersCount > 0 ) { + for($i = 0 ; $i<$filtersCount ; $i++) { + $filter = $finalFilters[$i]; + + if ( $filter instanceof PhingFilterReader ) { + + // This filter reader is an external class. + $className = $filter->getClassName(); + $classpath = $filter->getClasspath(); + $project = $filter->getProject(); + + if ( $className !== null ) { + $cls = Phing::import($className, $classpath); + $impl = new $cls(); + } + + if ( !($impl instanceof FilterReader) ) { + throw new Exception($className." does not extend phing.system.io.FilterReader"); + } + + $impl->setReader($instream); // chain + $impl->setProject($this->getProject()); // what about $project above ? + + if ( $impl instanceof Parameterizable ) { + $impl->setParameters($filter->getParams()); + } + + $instream = $impl; // now that it's been chained + + } elseif (($filter instanceof ChainableReader) && ($filter instanceof Reader)) { + if ( $this->getProject() !== null && ($filter instanceof BaseFilterReader) ) { + $filter->setProject($this->getProject()); + } + $instream = $filter->chain($instream); + } else { + throw new Exception("Cannot chain invalid filter: " . get_class($filter)); + } + } + } + + return $instream; + } + +} + +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/filters/util/IniFileTokenReader.php b/buildscripts/phing/classes/phing/filters/util/IniFileTokenReader.php new file mode 100644 index 00000000..34bc5943 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/util/IniFileTokenReader.php @@ -0,0 +1,96 @@ +. +*/ + +include_once 'phing/types/TokenReader.php'; +include_once 'phing/system/io/IOException.php'; +include_once 'phing/filters/ReplaceTokens.php'; // For class Token + +/** + * Class that allows reading tokens from INI files. + * + * @author Manuel Holtgewe + * @version $Revision: 1.7 $ + * @package phing.filters.util + */ +class IniFileTokenReader extends TokenReader { + + /** + * Holds the path to the INI file that is to be read. + * @var object Reference to a PhingFile Object representing + * the path to the INI file. + */ + private $file = null; + + /** + * @var string Sets the section to load from the INI file. + * if omitted, all sections are loaded. + */ + private $section = null; + + /** + * Reads the next token from the INI file + * + * @throws IOException On error + */ + function readToken() { + if ($this->file === null) { + throw new BuildException("No File set for IniFileTokenReader"); + } + + static $tokens = null; + if ($tokens === null) { + $tokens = array(); + $arr = parse_ini_file($this->file->getAbsolutePath(), true); + if ($this->section === null) { + foreach ($arr as $sec_name => $values) { + foreach($arr[$sec_name] as $key => $value) { + $tok = new Token; + $tok->setKey($key); + $tok->setValue($value); + $tokens[] = $tok; + } + } + } else if (isset($arr[$this->section])) { + foreach ($arr[$this->section] as $key => $value) { + $tok = new Token; + $tok->setKey($key); + $tok->setValue($value); + $tokens[] = $tok; + } + } + } + + if (count($tokens) > 0) { + return array_pop($tokens); + } else + return null; + } + + function setFile(PhingFile $file) { + $this->file = $file; + } + + function setSection($str) { + $this->section = (string) $str; + } +} + +?> diff --git a/buildscripts/phing/classes/phing/input/DefaultInputHandler.php b/buildscripts/phing/classes/phing/input/DefaultInputHandler.php new file mode 100644 index 00000000..8ce76cdd --- /dev/null +++ b/buildscripts/phing/classes/phing/input/DefaultInputHandler.php @@ -0,0 +1,82 @@ +. + */ + +require_once 'phing/input/InputHandler.php'; +include_once 'phing/system/io/ConsoleReader.php'; + +/** + * Prompts using print(); reads input from Console. + * + * @author Hans Lellelid (Phing) + * @author Stefan Bodewig (Ant) + * @version $Revision: 1.6 $ + * @package phing.input + */ +class DefaultInputHandler implements InputHandler { + + /** + * Prompts and requests input. May loop until a valid input has + * been entered. + * @throws BuildException + */ + public function handleInput(InputRequest $request) { + $prompt = $this->getPrompt($request); + $in = new ConsoleReader(); + do { + print $prompt; + try { + $input = $in->readLine(); + if ($input === "" && ($request->getDefaultValue() !== null) ) { + $input = $request->getDefaultValue(); + } + $request->setInput($input); + } catch (Exception $e) { + throw new BuildException("Failed to read input from Console.", $e); + } + } while (!$request->isInputValid()); + } + + /** + * Constructs user prompt from a request. + * + *

                                                This implementation adds (choice1,choice2,choice3,...) to the + * prompt for MultipleChoiceInputRequests.

                                                + * + * @param $request the request to construct the prompt for. + * Must not be null. + */ + protected function getPrompt(InputRequest $request) { + $prompt = $request->getPrompt(); + + // use is_a() to avoid needing the class to be loaded + if (is_a($request, 'YesNoInputRequest')) { // (yes/no) + $prompt .= '(' . implode('/', $request->getChoices()) .')'; + } elseif (is_a($request, 'MultipleChoiceInputRequest')) { // (a,b,c,d) + $prompt .= '(' . implode(',', $request->getChoices()) . ')'; + } + if ($request->getDefaultValue() !== null) { + $prompt .= ' ['.$request->getDefaultValue().']'; + } + $pchar = $request->getPromptChar(); + return $prompt . ($pchar ? $pchar . ' ' : ' '); + } +} diff --git a/buildscripts/phing/classes/phing/input/InputHandler.php b/buildscripts/phing/classes/phing/input/InputHandler.php new file mode 100644 index 00000000..68fad7b5 --- /dev/null +++ b/buildscripts/phing/classes/phing/input/InputHandler.php @@ -0,0 +1,45 @@ +. + */ + +/** + * Plugin to Phing to handle requests for user input. + * + * @author Stefan Bodewig + * @version $Revision: 1.3 $ + * @package phing.input + */ +interface InputHandler { + + /** + * Handle the request encapsulated in the argument. + * + *

                                                Precondition: the request.getPrompt will return a non-null + * value.

                                                + * + *

                                                Postcondition: request.getInput will return a non-null + * value, request.isInputValid will return true.

                                                + * @return void + * @throws BuildException + */ + public function handleInput(InputRequest $request); + +} diff --git a/buildscripts/phing/classes/phing/input/InputRequest.php b/buildscripts/phing/classes/phing/input/InputRequest.php new file mode 100644 index 00000000..7bfe8def --- /dev/null +++ b/buildscripts/phing/classes/phing/input/InputRequest.php @@ -0,0 +1,107 @@ +. + */ + +/** + * Encapsulates an input request. + * + * @author Hans Lellelid (Phing) + * @author Stefan Bodewig (Ant) + * @version $Revision: 1.4 $ + * @package phing.input + */ +class InputRequest { + + protected $prompt; + protected $input; + protected $defaultValue; + protected $promptChar; + + /** + * @param string $prompt The prompt to show to the user. Must not be null. + */ + public function __construct($prompt) { + if ($prompt === null) { + throw new BuildException("prompt must not be null"); + } + $this->prompt = $prompt; + } + + /** + * Retrieves the prompt text. + */ + public function getPrompt() { + return $this->prompt; + } + + /** + * Sets the user provided input. + */ + public function setInput($input) { + $this->input = $input; + } + + /** + * Is the user input valid? + */ + public function isInputValid() { + return true; + } + + /** + * Retrieves the user input. + */ + public function getInput() { + return $this->input; + } + + /** + * Set the default value to use. + * @param mixed $v + */ + public function setDefaultValue($v) { + $this->defaultValue = $v; + } + + /** + * Return the default value to use. + * @return mixed + */ + public function getDefaultValue() { + return $this->defaultValue; + } + + /** + * Set the default value to use. + * @param string $c + */ + public function setPromptChar($c) { + $this->promptChar = $c; + } + + /** + * Return the default value to use. + * @return string + */ + public function getPromptChar() { + return $this->promptChar; + } +} diff --git a/buildscripts/phing/classes/phing/input/MultipleChoiceInputRequest.php b/buildscripts/phing/classes/phing/input/MultipleChoiceInputRequest.php new file mode 100644 index 00000000..d4ea1212 --- /dev/null +++ b/buildscripts/phing/classes/phing/input/MultipleChoiceInputRequest.php @@ -0,0 +1,58 @@ +. + */ + +require_once 'phing/input/InputRequest.php'; + +/** + * Encapsulates an input request. + * + * @author Stefan Bodewig + * @version $Revision: 1.5 $ + * @package phing.input + */ +class MultipleChoiceInputRequest extends InputRequest { + + protected $choices = array(); + + /** + * @param string $prompt The prompt to show to the user. Must not be null. + * @param array $choices holds all input values that are allowed. + * Must not be null. + */ + public function __construct($prompt, $choices) { + parent::__construct($prompt); + $this->choices = $choices; + } + + /** + * @return The possible values. + */ + public function getChoices() { + return $this->choices; + } + + /** + * @return true if the input is one of the allowed values. + */ + public function isInputValid() { + return in_array($this->getInput(), $this->choices); // not strict (?) + } +} diff --git a/buildscripts/phing/classes/phing/input/PropertyFileInputHandler.php b/buildscripts/phing/classes/phing/input/PropertyFileInputHandler.php new file mode 100644 index 00000000..e588cead --- /dev/null +++ b/buildscripts/phing/classes/phing/input/PropertyFileInputHandler.php @@ -0,0 +1,129 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "Ant" and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.tools.ant.input; + +import org.apache.tools.ant.BuildException; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; + +/** + * Reads input from a property file, the file name is read from the + * system property ant.input.properties, the prompt is the key for input. + * + * @author Stefan Bodewig + * @version $Revision: 1.1 $ + * @since Ant 1.5 + */ +public class PropertyFileInputHandler implements InputHandler { + private Properties props = null; + + /** + * Name of the system property we expect to hold the file name. + */ + public static final String FILE_NAME_KEY = "ant.input.properties"; + + /** + * Empty no-arg constructor. + */ + public PropertyFileInputHandler() { + } + + /** + * Picks up the input from a property, using the prompt as the + * name of the property. + * + * @exception BuildException if no property of that name can be found. + */ + public void handleInput(InputRequest request) throws BuildException { + readProps(); + + Object o = props.get(request.getPrompt()); + if (o == null) { + throw new BuildException("Unable to find input for \'" + + request.getPrompt()+"\'"); + } + request.setInput(o.toString()); + if (!request.isInputValid()) { + throw new BuildException("Found invalid input " + o + + " for \'" + request.getPrompt() + "\'"); + } + } + + /** + * Reads the properties file if it hasn't already been read. + */ + private synchronized void readProps() throws BuildException { + if (props == null) { + String propsFile = System.getProperty(FILE_NAME_KEY); + if (propsFile == null) { + throw new BuildException("System property " + + FILE_NAME_KEY + + " for PropertyFileInputHandler not" + + " set"); + } + + props = new Properties(); + + try { + props.load(new FileInputStream(propsFile)); + } catch (IOException e) { + throw new BuildException("Couldn't load " + propsFile, e); + } + } + } + +} diff --git a/buildscripts/phing/classes/phing/input/YesNoInputRequest.php b/buildscripts/phing/classes/phing/input/YesNoInputRequest.php new file mode 100644 index 00000000..e34863d5 --- /dev/null +++ b/buildscripts/phing/classes/phing/input/YesNoInputRequest.php @@ -0,0 +1,47 @@ +. + */ + +require_once 'phing/input/MultipleChoiceInputRequest.php'; + +/** + * Encapsulates an input request that returns a boolean (yes/no). + * + * @author Hans Lellelid + * @version $Revision: 1.4 $ + * @package phing.input + */ +class YesNoInputRequest extends MultipleChoiceInputRequest { + + /** + * @return true if the input is one of the allowed values. + */ + public function isInputValid() { + return StringHelper::isBoolean($this->input); + } + + /** + * Converts input to boolean. + * @return boolean + */ + public function getInput() { + return StringHelper::booleanValue($this->input); + } +} diff --git a/buildscripts/phing/classes/phing/lib/Capsule.php b/buildscripts/phing/classes/phing/lib/Capsule.php new file mode 100644 index 00000000..bab05486 --- /dev/null +++ b/buildscripts/phing/classes/phing/lib/Capsule.php @@ -0,0 +1,266 @@ + + * @version $Revision: 1.9 $ $Date: 2004/08/31 20:12:02 $ + */ +class Capsule { + + /** + * Look for templates here (if relative path provided). + * @var string + */ + protected $templatePath; + + /** + * Where should output files be written? + * (This is named inconsistently to be compatible w/ Texen.) + * @var string + */ + protected $outputDirectory; + + /** + * The variables that can be used by the templates. + * @var array Hash of variables. + */ + public $vars = array(); + + /** + * Has template been initialized. + */ + protected $initialized = false; + + /** + * Stores the pre-parse() include_path. + * @var string + */ + private $old_include_path; + + function __construct() { + } + + /** + * Clears one or several or all variables. + * @param mixed $which String name of var, or array of names. + * @return void + */ + function clear($which = null) { + if ($which === null) { + $this->vars = array(); + } elseif (is_array($which)) { + foreach($which as $var) { + unset($this->vars[$var]); + } + } else { + unset($this->vars[$which]); + } + } + + /** + * Set the basepath to use for template lookups. + * @param string $v + */ + function setTemplatePath($v) { + $this->templatePath = rtrim($v, DIRECTORY_SEPARATOR.'/'); + } + + /** + * Get the basepath to use for template lookups. + * @return string + */ + function getTemplatePath() { + return $this->templatePath; + } + + /** + * Set a basepath to use for output file creation. + * @param string $v + */ + function setOutputDirectory($v) { + $this->outputDirectory = rtrim($v, DIRECTORY_SEPARATOR.'/'); + } + + /** + * Get basepath to use for output file creation. + * @return string + */ + function getOutputDirectory() { + return $this->outputDirectory; + } + + /** + * Low overhead (no output buffering) method to simply dump template + * to buffer. + * + * @param string $__template + * @return void + * @throws Exception - if template cannot be found + */ + function display($__template) { + + // Prepend "private" variable names with $__ in this function + // to keep namespace conflict potential to a minimum. + + // Alias this class to $generator. + $generator = $this; + + if (isset($this->vars['this'])) { + throw new Exception("Assigning a variable named \$this to a context conflicts with class namespace."); + } + + // extract variables into local namespace + extract($this->vars); + + // prepend template path to include path, + // so that include "path/relative/to/templates"; can be used within templates + $__old_inc_path = ini_get('include_path'); + ini_set('include_path', $this->templatePath . PATH_SEPARATOR . $__old_inc_path); + + @ini_set('track_errors', true); + include $__template; + @ini_restore('track_errors'); + + // restore the include path + ini_set('include_path', $__old_inc_path); + + if (!empty($php_errormsg)) { + throw new Exception("Unable to parse template " . $__template . ": " . $php_errormsg); + } + } + + /** + * Fetches the results of a tempalte parse and either returns + * the string or writes results to a specified output file. + * + * @param string $template The template filename (relative to templatePath or absolute). + * @param string $outputFile If specified, contents of template will also be written to this file. + * @param boolean $append Should output be appended to source file? + * @return string The "parsed" template output. + * @throws Exception - if template not found. + */ + function parse($template, $outputFile = null, $append = false) { + + // main work done right here: + // hopefully this works recursively ... fingers crossed. + ob_start(); + + try { + $this->display($template); + } catch (Exception $e) { + ob_end_flush(); // flush the output on error (so we can see up to what point it parsed everything) + throw $e; + } + + $output = ob_get_contents(); + ob_end_clean(); + + if ($outputFile !== null) { + $outputFile = $this->resolvePath($outputFile, $this->outputDirectory); + + $flags = null; + if ($append) $flags = FILE_APPEND; + + if (!file_put_contents($outputFile, $output, $flags) && $output != "") { + throw new Exception("Unable to write output to " . $outputFile); + } + } + + return $output; + } + + /** + * This returns a "best guess" path for the given file. + * + * @param string $file File name or possibly absolute path. + * @param string $basepath The basepath that should be prepended if $file is not absolute. + * @return string "Best guess" path for this file. + */ + protected function resolvePath($file, $basepath) { + if ( !($file{0} == DIRECTORY_SEPARATOR || $file{0} == '/') + // also account for C:\ style path + && !($file{1} == ':' && ($file{2} == DIRECTORY_SEPARATOR || $file{2} == '/'))) { + if ($basepath != null) { + $file = $basepath . DIRECTORY_SEPARATOR . $file; + } + } + return $file; + } + + /** + * Gets value of specified var or NULL if var has not been put(). + * @param string $name Variable name to retrieve. + * @return mixed + */ + function get($name) { + if (!isset($this->vars[$name])) return null; + return $this->vars[$name]; + } + + /** + * Merges in passed hash to vars array. + * + * Given an array like: + * + * array( 'myvar' => 'Hello', + * 'myvar2' => 'Hello') + * + * Resulting template will have access to $myvar and $myvar2. + * + * @param array $vars + * @param boolean $recursiveMerge Should matching keys be recursively merged? + * @return void + */ + function putAll($vars, $recursiveMerge = false) { + if ($recursiveMerge) { + $this->vars = array_merge_recursive($this->vars, $vars); + } else { + $this->vars = array_merge($this->vars, $vars); + } + } + + /** + * Adds a variable to the context. + * + * Resulting template will have access to ${$name$} variable. + * + * @param string $name + * @param mixed $value + */ + function put($name, $value) { + $this->vars[$name] = $value; + } + + /** + * Put a variable into the context, assigning it by reference. + * This means that if the template modifies the variable, then it + * will also be modified in the context. + * + * @param $name + * @param &$value + */ + function putRef($name, &$value) { + $this->vars[$name] = &$value; + } + + /** + * Makes a copy of the value and puts it into the context. + * This is primarily to force copying (cloning) of objects, rather + * than the default behavior which is to assign them by reference. + * @param string $name + * @param mixed $value + */ + function putCopy($name, $value) { + if (is_object($value)) { + $value = clone $value; + } + $this->vars[$name] = $value; + } + +} \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/lib/Zip.php b/buildscripts/phing/classes/phing/lib/Zip.php new file mode 100644 index 00000000..70d31595 --- /dev/null +++ b/buildscripts/phing/classes/phing/lib/Zip.php @@ -0,0 +1,3588 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Zip.php,v 1.3 2005/12/27 16:05:57 hlellelid Exp $ + + // ----- Constants + define( 'ARCHIVE_ZIP_READ_BLOCK_SIZE', 2048 ); + + // ----- File list separator + define( 'ARCHIVE_ZIP_SEPARATOR', ',' ); + + // ----- Optional static temporary directory + // By default temporary files are generated in the script current + // path. + // If defined : + // - MUST BE terminated by a '/'. + // - MUST be a valid, already created directory + // Samples : + // define( 'ARCHIVE_ZIP_TEMPORARY_DIR', '/temp/' ); + // define( 'ARCHIVE_ZIP_TEMPORARY_DIR', 'C:/Temp/' ); + define( 'ARCHIVE_ZIP_TEMPORARY_DIR', '' ); + + // ----- Error codes + define( 'ARCHIVE_ZIP_ERR_NO_ERROR', 0 ); + define( 'ARCHIVE_ZIP_ERR_WRITE_OPEN_FAIL', -1 ); + define( 'ARCHIVE_ZIP_ERR_READ_OPEN_FAIL', -2 ); + define( 'ARCHIVE_ZIP_ERR_INVALID_PARAMETER', -3 ); + define( 'ARCHIVE_ZIP_ERR_MISSING_FILE', -4 ); + define( 'ARCHIVE_ZIP_ERR_FILENAME_TOO_LONG', -5 ); + define( 'ARCHIVE_ZIP_ERR_INVALID_ZIP', -6 ); + define( 'ARCHIVE_ZIP_ERR_BAD_EXTRACTED_FILE', -7 ); + define( 'ARCHIVE_ZIP_ERR_DIR_CREATE_FAIL', -8 ); + define( 'ARCHIVE_ZIP_ERR_BAD_EXTENSION', -9 ); + define( 'ARCHIVE_ZIP_ERR_BAD_FORMAT', -10 ); + define( 'ARCHIVE_ZIP_ERR_DELETE_FILE_FAIL', -11 ); + define( 'ARCHIVE_ZIP_ERR_RENAME_FILE_FAIL', -12 ); + define( 'ARCHIVE_ZIP_ERR_BAD_CHECKSUM', -13 ); + define( 'ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP', -14 ); + define( 'ARCHIVE_ZIP_ERR_MISSING_OPTION_VALUE', -15 ); + define( 'ARCHIVE_ZIP_ERR_INVALID_PARAM_VALUE', -16 ); + + // ----- Warning codes + define( 'ARCHIVE_ZIP_WARN_NO_WARNING', 0 ); + define( 'ARCHIVE_ZIP_WARN_FILE_EXIST', 1 ); + + // ----- Methods parameters + define( 'ARCHIVE_ZIP_PARAM_PATH', 'path' ); + define( 'ARCHIVE_ZIP_PARAM_ADD_PATH', 'add_path' ); + define( 'ARCHIVE_ZIP_PARAM_REMOVE_PATH', 'remove_path' ); + define( 'ARCHIVE_ZIP_PARAM_REMOVE_ALL_PATH', 'remove_all_path' ); + define( 'ARCHIVE_ZIP_PARAM_SET_CHMOD', 'set_chmod' ); + define( 'ARCHIVE_ZIP_PARAM_EXTRACT_AS_STRING', 'extract_as_string' ); + define( 'ARCHIVE_ZIP_PARAM_NO_COMPRESSION', 'no_compression' ); + define( 'ARCHIVE_ZIP_PARAM_BY_NAME', 'by_name' ); + define( 'ARCHIVE_ZIP_PARAM_BY_INDEX', 'by_index' ); + define( 'ARCHIVE_ZIP_PARAM_BY_EREG', 'by_ereg' ); + define( 'ARCHIVE_ZIP_PARAM_BY_PREG', 'by_preg' ); + + define( 'ARCHIVE_ZIP_PARAM_PRE_EXTRACT', 'callback_pre_extract' ); + define( 'ARCHIVE_ZIP_PARAM_POST_EXTRACT', 'callback_post_extract' ); + define( 'ARCHIVE_ZIP_PARAM_PRE_ADD', 'callback_pre_add' ); + define( 'ARCHIVE_ZIP_PARAM_POST_ADD', 'callback_post_add' ); + + + +/** +* Class for manipulating zip archive files +* +* A class which provided common methods to manipulate ZIP formatted +* archive files. +* It provides creation, extraction, deletion and add features. +* +* @author Vincent Blavet +* @version $Revision: 1.3 $ +* @package phing.lib +*/ +class Archive_Zip +{ + /** + * The filename of the zip archive. + * + * @var string Name of the Zip file + */ + var $_zipname=''; + + /** + * File descriptor of the opened Zip file. + * + * @var int Internal zip file descriptor + */ + var $_zip_fd=0; + + /** + * @var int last error code + */ + var $_error_code=1; + + /** + * @var string Last error description + */ + var $_error_string=''; + + // {{{ constructor + /** + * Archive_Zip Class constructor. This flavour of the constructor only + * declare a new Archive_Zip object, identifying it by the name of the + * zip file. + * + * @param string $p_zipname The name of the zip archive to create + * @access public + */ + function __construct($p_zipname) + { + if (!extension_loaded('zlib')) { + throw new Exception("The extension 'zlib' couldn't be found.\n". + "Please make sure your version of PHP was built ". + "with 'zlib' support."); + } + + // ----- Set the attributes + $this->_zipname = $p_zipname; + $this->_zip_fd = 0; + } + // }}} + + // {{{ create() + /** + * This method creates a Zip Archive with the filename set with + * the constructor. + * The files and directories indicated in $p_filelist + * are added in the archive. + * When a directory is in the list, the directory and its content is added + * in the archive. + * The methods takes a variable list of parameters in $p_params. + * The supported parameters for this method are : + * 'add_path' : Add a path to the archived files. + * 'remove_path' : Remove the specified 'root' path of the archived files. + * 'remove_all_path' : Remove all the path of the archived files. + * 'no_compression' : The archived files will not be compressed. + * + * @access public + * @param mixed $p_filelist The list of the files or folders to add. + * It can be a string with filenames separated + * by a comma, or an array of filenames. + * @param mixed $p_params An array of variable parameters and values. + * @return mixed An array of file description on success, + * an error code on error + */ + function create($p_filelist, $p_params=0) + { + $this->_errorReset(); + + // ----- Set default values + if ($p_params === 0) { + $p_params = array(); + } + if ($this->_check_parameters($p_params, + array('no_compression' => false, + 'add_path' => "", + 'remove_path' => "", + 'remove_all_path' => false)) != 1) { + return 0; + } + + // ----- Look if the $p_filelist is really an array + $p_result_list = array(); + if (is_array($p_filelist)) { + $v_result = $this->_create($p_filelist, $p_result_list, $p_params); + } + + // ----- Look if the $p_filelist is a string + else if (is_string($p_filelist)) { + // ----- Create a list with the elements from the string + $v_list = explode(ARCHIVE_ZIP_SEPARATOR, $p_filelist); + + $v_result = $this->_create($v_list, $p_result_list, $p_params); + } + + // ----- Invalid variable + else { + $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, + 'Invalid variable type p_filelist'); + $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER; + } + + if ($v_result != 1) { + return 0; + } + + return $p_result_list; + } + // }}} + + // {{{ add() + /** + * This method add files or directory in an existing Zip Archive. + * If the Zip Archive does not exist it is created. + * The files and directories to add are indicated in $p_filelist. + * When a directory is in the list, the directory and its content is added + * in the archive. + * The methods takes a variable list of parameters in $p_params. + * The supported parameters for this method are : + * 'add_path' : Add a path to the archived files. + * 'remove_path' : Remove the specified 'root' path of the archived files. + * 'remove_all_path' : Remove all the path of the archived files. + * 'no_compression' : The archived files will not be compressed. + * 'callback_pre_add' : A callback function that will be called before + * each entry archiving. + * 'callback_post_add' : A callback function that will be called after + * each entry archiving. + * + * @access public + * @param mixed $p_filelist The list of the files or folders to add. + * It can be a string with filenames separated + * by a comma, or an array of filenames. + * @param mixed $p_params An array of variable parameters and values. + * @return mixed An array of file description on success, + * 0 on an unrecoverable failure, an error code is logged. + */ + function add($p_filelist, $p_params=0) + { + $this->_errorReset(); + + // ----- Set default values + if ($p_params === 0) { + $p_params = array(); + } + if ($this->_check_parameters($p_params, + array ('no_compression' => false, + 'add_path' => '', + 'remove_path' => '', + 'remove_all_path' => false, + 'callback_pre_add' => '', + 'callback_post_add' => '')) != 1) { + return 0; + } + + // ----- Look if the $p_filelist is really an array + $p_result_list = array(); + if (is_array($p_filelist)) { + // ----- Call the create fct + $v_result = $this->_add($p_filelist, $p_result_list, $p_params); + } + + // ----- Look if the $p_filelist is a string + else if (is_string($p_filelist)) { + // ----- Create a list with the elements from the string + $v_list = explode(ARCHIVE_ZIP_SEPARATOR, $p_filelist); + + // ----- Call the create fct + $v_result = $this->_add($v_list, $p_result_list, $p_params); + } + + // ----- Invalid variable + else { + $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, + "add() : Invalid variable type p_filelist"); + $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER; + } + + if ($v_result != 1) { + return 0; + } + + // ----- Return the result list + return $p_result_list; + } + // }}} + + // {{{ listContent() + /** + * This method gives the names and properties of the files and directories + * which are present in the zip archive. + * The properties of each entries in the list are : + * filename : Name of the file. + * For create() or add() it's the filename given by the user. + * For an extract() it's the filename of the extracted file. + * stored_filename : Name of the file / directory stored in the archive. + * size : Size of the stored file. + * compressed_size : Size of the file's data compressed in the archive + * (without the zip headers overhead) + * mtime : Last known modification date of the file (UNIX timestamp) + * comment : Comment associated with the file + * folder : true | false (indicates if the entry is a folder) + * index : index of the file in the archive (-1 when not available) + * status : status of the action on the entry (depending of the action) : + * Values are : + * ok : OK ! + * filtered : the file/dir was not extracted (filtered by user) + * already_a_directory : the file can't be extracted because a + * directory with the same name already + * exists + * write_protected : the file can't be extracted because a file + * with the same name already exists and is + * write protected + * newer_exist : the file was not extracted because a newer + * file already exists + * path_creation_fail : the file is not extracted because the + * folder does not exists and can't be + * created + * write_error : the file was not extracted because there was a + * error while writing the file + * read_error : the file was not extracted because there was a + * error while reading the file + * invalid_header : the file was not extracted because of an + * archive format error (bad file header) + * Note that each time a method can continue operating when there + * is an error on a single file, the error is only logged in the file status. + * + * @access public + * @return mixed An array of file description on success, + * 0 on an unrecoverable failure, an error code is logged. + */ + function listContent() + { + $this->_errorReset(); + + // ----- Check archive + if (!$this->_checkFormat()) { + return(0); + } + + $v_list = array(); + if ($this->_list($v_list) != 1) { + unset($v_list); + return(0); + } + + return $v_list; + } + // }}} + + // {{{ extract() + /** + * This method extract the files and folders which are in the zip archive. + * It can extract all the archive or a part of the archive by using filter + * feature (extract by name, by index, by ereg, by preg). The extraction + * can occur in the current path or an other path. + * All the advanced features are activated by the use of variable + * parameters. + * The return value is an array of entry descriptions which gives + * information on extracted files (See listContent()). + * The method may return a success value (an array) even if some files + * are not correctly extracted (see the file status in listContent()). + * The supported variable parameters for this method are : + * 'add_path' : Path where the files and directories are to be extracted + * 'remove_path' : First part ('root' part) of the memorized path + * (if similar) to remove while extracting. + * 'remove_all_path' : Remove all the memorized path while extracting. + * 'extract_as_string' : + * 'set_chmod' : After the extraction of the file the indicated mode + * will be set. + * 'by_name' : It can be a string with file/dir names separated by ',', + * or an array of file/dir names to extract from the archive. + * 'by_index' : A string with range of indexes separated by ',', + * (sample "1,3-5,12"). + * 'by_ereg' : A regular expression (ereg) that must match the extracted + * filename. + * 'by_preg' : A regular expression (preg) that must match the extracted + * filename. + * 'callback_pre_extract' : A callback function that will be called before + * each entry extraction. + * 'callback_post_extract' : A callback function that will be called after + * each entry extraction. + * + * @access public + * @param mixed $p_params An array of variable parameters and values. + * @return mixed An array of file description on success, + * 0 on an unrecoverable failure, an error code is logged. + */ + function extract($p_params=0) + { + + $this->_errorReset(); + + // ----- Check archive + if (!$this->_checkFormat()) { + return(0); + } + + // ----- Set default values + if ($p_params === 0) { + $p_params = array(); + } + if ($this->_check_parameters($p_params, + array ('extract_as_string' => false, + 'add_path' => '', + 'remove_path' => '', + 'remove_all_path' => false, + 'callback_pre_extract' => '', + 'callback_post_extract' => '', + 'set_chmod' => 0, + 'by_name' => '', + 'by_index' => '', + 'by_ereg' => '', + 'by_preg' => '') ) != 1) { + return 0; + } + + // ----- Call the extracting fct + $v_list = array(); + if ($this->_extractByRule($v_list, $p_params) != 1) { + unset($v_list); + return(0); + } + + return $v_list; + } + // }}} + + + // {{{ delete() + /** + * This methods delete archive entries in the zip archive. + * Notice that at least one filtering rule (set by the variable parameter + * list) must be set. + * Also notice that if you delete a folder entry, only the folder entry + * is deleted, not all the files bellonging to this folder. + * The supported variable parameters for this method are : + * 'by_name' : It can be a string with file/dir names separated by ',', + * or an array of file/dir names to delete from the archive. + * 'by_index' : A string with range of indexes separated by ',', + * (sample "1,3-5,12"). + * 'by_ereg' : A regular expression (ereg) that must match the extracted + * filename. + * 'by_preg' : A regular expression (preg) that must match the extracted + * filename. + * + * @access public + * @param mixed $p_params An array of variable parameters and values. + * @return mixed An array of file description on success, + * 0 on an unrecoverable failure, an error code is logged. + */ + function delete($p_params) + { + $this->_errorReset(); + + // ----- Check archive + if (!$this->_checkFormat()) { + return(0); + } + + // ----- Set default values + if ($this->_check_parameters($p_params, + array ('by_name' => '', + 'by_index' => '', + 'by_ereg' => '', + 'by_preg' => '') ) != 1) { + return 0; + } + + // ----- Check that at least one rule is set + if ( ($p_params['by_name'] == '') + && ($p_params['by_index'] == '') + && ($p_params['by_ereg'] == '') + && ($p_params['by_preg'] == '')) { + $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, + 'At least one filtering rule must' + .' be set as parameter'); + return 0; + } + + // ----- Call the delete fct + $v_list = array(); + if ($this->_deleteByRule($v_list, $p_params) != 1) { + unset($v_list); + return(0); + } + + return $v_list; + } + // }}} + + // {{{ properties() + /** + * This method gives the global properties of the archive. + * The properties are : + * nb : Number of files in the archive + * comment : Comment associated with the archive file + * status : not_exist, ok + * + * @access public + * @param mixed $p_params {Description} + * @return mixed An array with the global properties or 0 on error. + */ + function properties() + { + $this->_errorReset(); + + // ----- Check archive + if (!$this->_checkFormat()) { + return(0); + } + + // ----- Default properties + $v_prop = array(); + $v_prop['comment'] = ''; + $v_prop['nb'] = 0; + $v_prop['status'] = 'not_exist'; + + // ----- Look if file exists + if (@is_file($this->_zipname)) { + // ----- Open the zip file + if (($this->_zip_fd = @fopen($this->_zipname, 'rb')) == 0) { + $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, + 'Unable to open archive \''.$this->_zipname + .'\' in binary read mode'); + return 0; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) { + return 0; + } + + $this->_closeFd(); + + // ----- Set the user attributes + $v_prop['comment'] = $v_central_dir['comment']; + $v_prop['nb'] = $v_central_dir['entries']; + $v_prop['status'] = 'ok'; + } + + return $v_prop; + } + // }}} + + + // {{{ duplicate() + /** + * This method creates an archive by copying the content of an other one. + * If the archive already exist, it is replaced by the new one without + * any warning. + * + * @access public + * @param mixed $p_archive It can be a valid Archive_Zip object or + * the filename of a valid zip archive. + * @return integer 1 on success, 0 on failure. + */ + function duplicate($p_archive) + { + $this->_errorReset(); + + // ----- Look if the $p_archive is a Archive_Zip object + if ( (is_object($p_archive)) + && (strtolower(get_class($p_archive)) == 'archive_zip')) { + $v_result = $this->_duplicate($p_archive->_zipname); + } + + // ----- Look if the $p_archive is a string (so a filename) + else if (is_string($p_archive)) { + // ----- Check that $p_archive is a valid zip file + // TBC : Should also check the archive format + if (!is_file($p_archive)) { + $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE, + "No file with filename '".$p_archive."'"); + $v_result = ARCHIVE_ZIP_ERR_MISSING_FILE; + } + else { + $v_result = $this->_duplicate($p_archive); + } + } + + // ----- Invalid variable + else { + $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, + "Invalid variable type p_archive_to_add"); + $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER; + } + + return $v_result; + } + // }}} + + // {{{ merge() + /** + * This method merge a valid zip archive at the end of the + * archive identified by the Archive_Zip object. + * If the archive ($this) does not exist, the merge becomes a duplicate. + * If the archive to add does not exist, the merge is a success. + * + * @access public + * @param mixed $p_archive_to_add It can be a valid Archive_Zip object or + * the filename of a valid zip archive. + * @return integer 1 on success, 0 on failure. + */ + function merge($p_archive_to_add) + { + $v_result = 1; + $this->_errorReset(); + + // ----- Check archive + if (!$this->_checkFormat()) { + return(0); + } + + // ----- Look if the $p_archive_to_add is a Archive_Zip object + if ( (is_object($p_archive_to_add)) + && (strtolower(get_class($p_archive_to_add)) == 'archive_zip')) { + $v_result = $this->_merge($p_archive_to_add); + } + + // ----- Look if the $p_archive_to_add is a string (so a filename) + else if (is_string($p_archive_to_add)) { + // ----- Create a temporary archive + $v_object_archive = new Archive_Zip($p_archive_to_add); + + // ----- Merge the archive + $v_result = $this->_merge($v_object_archive); + } + + // ----- Invalid variable + else { + $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, + "Invalid variable type p_archive_to_add"); + $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER; + } + + return $v_result; + } + // }}} + + // {{{ errorCode() + /** + * Method that gives the lastest error code. + * + * @access public + * @return integer The error code value. + */ + function errorCode() + { + return($this->_error_code); + } + // }}} + + // {{{ errorName() + /** + * This method gives the latest error code name. + * + * @access public + * @param boolean $p_with_code If true, gives the name and the int value. + * @return string The error name. + */ + function errorName($p_with_code=false) + { + $v_const_list = get_defined_constants(); + + // ----- Extract error constants from all const. + for (reset($v_const_list); + list($v_key, $v_value) = each($v_const_list);) { + if (substr($v_key, 0, strlen('ARCHIVE_ZIP_ERR_')) + =='ARCHIVE_ZIP_ERR_') { + $v_error_list[$v_key] = $v_value; + } + } + + // ----- Search the name form the code value + $v_key=array_search($this->_error_code, $v_error_list, true); + if ($v_key!=false) { + $v_value = $v_key; + } + else { + $v_value = 'NoName'; + } + + if ($p_with_code) { + return($v_value.' ('.$this->_error_code.')'); + } + else { + return($v_value); + } + } + // }}} + + // {{{ errorInfo() + /** + * This method returns the description associated with the latest error. + * + * @access public + * @param boolean $p_full If set to true gives the description with the + * error code, the name and the description. + * If set to false gives only the description + * and the error code. + * @return string The error description. + */ + function errorInfo($p_full=false) + { + if ($p_full) { + return($this->errorName(true)." : ".$this->_error_string); + } + else { + return($this->_error_string." [code ".$this->_error_code."]"); + } + } + // }}} + + +// ----------------------------------------------------------------------------- +// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS ***** +// ***** ***** +// ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY ***** +// ----------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _checkFormat() + // Description : + // This method check that the archive exists and is a valid zip archive. + // Several level of check exists. (futur) + // Parameters : + // $p_level : Level of check. Default 0. + // 0 : Check the first bytes (magic codes) (default value)) + // 1 : 0 + Check the central directory (futur) + // 2 : 1 + Check each file header (futur) + // Return Values : + // true on success, + // false on error, the error code is set. + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_checkFormat() + * + * { Description } + * + * @param integer $p_level + */ + function _checkFormat($p_level=0) + { + $v_result = true; + + // ----- Reset the error handler + $this->_errorReset(); + + // ----- Look if the file exits + if (!is_file($this->_zipname)) { + // ----- Error log + $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE, + "Missing archive file '".$this->_zipname."'"); + return(false); + } + + // ----- Check that the file is readeable + if (!is_readable($this->_zipname)) { + // ----- Error log + $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, + "Unable to read archive '".$this->_zipname."'"); + return(false); + } + + // ----- Check the magic code + // TBC + + // ----- Check the central header + // TBC + + // ----- Check each file header + // TBC + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _create() + // Description : + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_create() + * + * { Description } + * + */ + function _create($p_list, &$p_result_list, &$p_params) + { + $v_result=1; + $v_list_detail = array(); + + $p_add_dir = $p_params['add_path']; + $p_remove_dir = $p_params['remove_path']; + $p_remove_all_dir = $p_params['remove_all_path']; + + // ----- Open the file in write mode + if (($v_result = $this->_openFd('wb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Add the list of files + $v_result = $this->_addList($p_list, $p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params); + + // ----- Close + $this->_closeFd(); + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _add() + // Description : + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_add() + * + * { Description } + * + */ + function _add($p_list, &$p_result_list, &$p_params) + { + $v_result=1; + $v_list_detail = array(); + + $p_add_dir = $p_params['add_path']; + $p_remove_dir = $p_params['remove_path']; + $p_remove_all_dir = $p_params['remove_all_path']; + + // ----- Look if the archive exists or is empty and need to be created + if ((!is_file($this->_zipname)) || (filesize($this->_zipname) == 0)) { + $v_result = $this->_create($p_list, $p_result_list, $p_params); + return $v_result; + } + + // ----- Open the zip file + if (($v_result=$this->_openFd('rb')) != 1) { + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) + { + $this->_closeFd(); + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->_zip_fd); + + // ----- Creates a temporay file + $v_zip_temp_name = ARCHIVE_ZIP_TEMPORARY_DIR.uniqid('archive_zip-').'.tmp'; + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) + { + $this->_closeFd(); + + $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, + 'Unable to open temporary file \'' + .$v_zip_temp_name.'\' in binary write mode'); + return Archive_Zip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the + // central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) + { + $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE + ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->_zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to + // use the following methods on the temporary fil and not the real archive + $v_swap = $this->_zip_fd; + $this->_zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->_addFileList($p_list, $v_header_list, + $p_add_dir, $p_remove_dir, + $p_remove_all_dir, $p_params)) != 1) + { + fclose($v_zip_temp_fd); + $this->_closeFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->_zip_fd); + + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE + ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->_zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Create the Central Dir files header + for ($i=0, $v_count=0; $i_writeCentralFileHeader($v_header_list[$i]))!=1) { + fclose($v_zip_temp_fd); + $this->_closeFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + $v_count++; + } + + // ----- Transform the header to a 'usable' info + $this->_convertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = ''; + + // ----- Calculate the size of the central header + $v_size = @ftell($this->_zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->_writeCentralHeader($v_count + +$v_central_dir['entries'], + $v_size, $v_offset, + $v_comment)) != 1) { + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } + + // ----- Swap back the file descriptor + $v_swap = $this->_zip_fd; + $this->_zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Close + $this->_closeFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->_zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->_zipname); + $this->_tool_Rename($v_zip_temp_name, $this->_zipname); + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _openFd() + // Description : + // Parameters : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_openFd() + * + * { Description } + * + */ + function _openFd($p_mode) + { + $v_result=1; + + // ----- Look if already open + if ($this->_zip_fd != 0) + { + $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, + 'Zip file \''.$this->_zipname.'\' already open'); + return Archive_Zip::errorCode(); + } + + // ----- Open the zip file + if (($this->_zip_fd = @fopen($this->_zipname, $p_mode)) == 0) + { + $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, + 'Unable to open archive \''.$this->_zipname + .'\' in '.$p_mode.' mode'); + return Archive_Zip::errorCode(); + } + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _closeFd() + // Description : + // Parameters : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_closeFd() + * + * { Description } + * + */ + function _closeFd() + { + $v_result=1; + + if ($this->_zip_fd != 0) + @fclose($this->_zip_fd); + $this->_zip_fd = 0; + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _addList() + // Description : + // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is + // different from the real path of the file. This is usefull if you want to have PclTar + // running in any directory, and memorize relative path from an other directory. + // Parameters : + // $p_list : An array containing the file or directory names to add in the tar + // $p_result_list : list of added files with their properties (specially the status field) + // $p_add_dir : Path to add in the filename path archived + // $p_remove_dir : Path to remove in the filename path archived + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_addList() + * + * { Description } + * + */ + function _addList($p_list, &$p_result_list, + $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_params) + { + $v_result=1; + + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->_addFileList($p_list, $v_header_list, + $p_add_dir, $p_remove_dir, + $p_remove_all_dir, $p_params)) != 1) { + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->_zip_fd); + + // ----- Create the Central Dir files header + for ($i=0,$v_count=0; $i_writeCentralFileHeader($v_header_list[$i])) != 1) { + return $v_result; + } + $v_count++; + } + + // ----- Transform the header to a 'usable' info + $this->_convertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = ''; + + // ----- Calculate the size of the central header + $v_size = @ftell($this->_zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->_writeCentralHeader($v_count, $v_size, $v_offset, + $v_comment)) != 1) + { + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _addFileList() + // Description : + // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is + // different from the real path of the file. This is usefull if you want to + // run the lib in any directory, and memorize relative path from an other directory. + // Parameters : + // $p_list : An array containing the file or directory names to add in the tar + // $p_result_list : list of added files with their properties (specially the status field) + // $p_add_dir : Path to add in the filename path archived + // $p_remove_dir : Path to remove in the filename path archived + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_addFileList() + * + * { Description } + * + */ + function _addFileList($p_list, &$p_result_list, + $p_add_dir, $p_remove_dir, $p_remove_all_dir, + &$p_params) + { + $v_result=1; + $v_header = array(); + + // ----- Recuperate the current number of elt in list + $v_nb = sizeof($p_result_list); + + // ----- Loop on the files + for ($j=0; ($j_tool_TranslateWinPath($p_list[$j], false); + + // ----- Skip empty file names + if ($p_filename == "") + { + continue; + } + + // ----- Check the filename + if (!file_exists($p_filename)) + { + $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE, + "File '$p_filename' does not exists"); + return Archive_Zip::errorCode(); + } + + // ----- Look if it is a file or a dir with no all pathnre move + if ((is_file($p_filename)) || ((is_dir($p_filename)) && !$p_remove_all_dir)) { + // ----- Add the file + if (($v_result = $this->_addFile($p_filename, $v_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params)) != 1) + { + // ----- Return status + return $v_result; + } + + // ----- Store the file infos + $p_result_list[$v_nb++] = $v_header; + } + + // ----- Look for directory + if (is_dir($p_filename)) + { + + // ----- Look for path + if ($p_filename != ".") + $v_path = $p_filename."/"; + else + $v_path = ""; + + // ----- Read the directory for files and sub-directories + $p_hdir = opendir($p_filename); + $p_hitem = readdir($p_hdir); // '.' directory + $p_hitem = readdir($p_hdir); // '..' directory + while ($p_hitem = readdir($p_hdir)) + { + + // ----- Look for a file + if (is_file($v_path.$p_hitem)) + { + + // ----- Add the file + if (($v_result = $this->_addFile($v_path.$p_hitem, $v_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params)) != 1) + { + // ----- Return status + return $v_result; + } + + // ----- Store the file infos + $p_result_list[$v_nb++] = $v_header; + } + + // ----- Recursive call to _addFileList() + else + { + + // ----- Need an array as parameter + $p_temp_list[0] = $v_path.$p_hitem; + $v_result = $this->_addFileList($p_temp_list, $p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params); + + // ----- Update the number of elements of the list + $v_nb = sizeof($p_result_list); + } + } + + // ----- Free memory for the recursive loop + unset($p_temp_list); + unset($p_hdir); + unset($p_hitem); + } + } + + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _addFile() + // Description : + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_addFile() + * + * { Description } + * + */ + function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_params) + { + $v_result=1; + + if ($p_filename == "") + { + // ----- Error log + $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); + + // ----- Return + return Archive_Zip::errorCode(); + } + + // ----- Calculate the stored filename + $v_stored_filename = $p_filename; + + // ----- Look for all path to remove + if ($p_remove_all_dir) { + $v_stored_filename = basename($p_filename); + } + // ----- Look for partial path remove + else if ($p_remove_dir != "") + { + if (substr($p_remove_dir, -1) != '/') + $p_remove_dir .= "/"; + + if ((substr($p_filename, 0, 2) == "./") || (substr($p_remove_dir, 0, 2) == "./")) + { + if ((substr($p_filename, 0, 2) == "./") && (substr($p_remove_dir, 0, 2) != "./")) + $p_remove_dir = "./".$p_remove_dir; + if ((substr($p_filename, 0, 2) != "./") && (substr($p_remove_dir, 0, 2) == "./")) + $p_remove_dir = substr($p_remove_dir, 2); + } + + $v_compare = $this->_tool_PathInclusion($p_remove_dir, $p_filename); + if ($v_compare > 0) +// if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) + { + + if ($v_compare == 2) { + $v_stored_filename = ""; + } + else { + $v_stored_filename = substr($p_filename, strlen($p_remove_dir)); + } + } + } + // ----- Look for path to add + if ($p_add_dir != "") + { + if (substr($p_add_dir, -1) == "/") + $v_stored_filename = $p_add_dir.$v_stored_filename; + else + $v_stored_filename = $p_add_dir."/".$v_stored_filename; + } + + // ----- Filename (reduce the path of stored name) + $v_stored_filename = $this->_tool_PathReduction($v_stored_filename); + + + /* filename length moved after call-back in release 1.3 + // ----- Check the path length + if (strlen($v_stored_filename) > 0xFF) + { + // ----- Error log + $this->_errorLog(-5, "Stored file name is too long (max. 255) : '$v_stored_filename'"); + + // ----- Return + return Archive_Zip::errorCode(); + } + */ + + // ----- Set the file properties + clearstatcache(); + $p_header['version'] = 20; + $p_header['version_extracted'] = 10; + $p_header['flag'] = 0; + $p_header['compression'] = 0; + $p_header['mtime'] = filemtime($p_filename); + $p_header['crc'] = 0; + $p_header['compressed_size'] = 0; + $p_header['size'] = filesize($p_filename); + $p_header['filename_len'] = strlen($p_filename); + $p_header['extra_len'] = 0; + $p_header['comment_len'] = 0; + $p_header['disk'] = 0; + $p_header['internal'] = 0; + $p_header['external'] = (is_file($p_filename)?0xFE49FFE0:0x41FF0010); + $p_header['offset'] = 0; + $p_header['filename'] = $p_filename; + $p_header['stored_filename'] = $v_stored_filename; + $p_header['extra'] = ''; + $p_header['comment'] = ''; + $p_header['status'] = 'ok'; + $p_header['index'] = -1; + + // ----- Look for pre-add callback + if ( (isset($p_params[ARCHIVE_ZIP_PARAM_PRE_ADD])) + && ($p_params[ARCHIVE_ZIP_PARAM_PRE_ADD] != '')) { + + // ----- Generate a local information + $v_local_header = array(); + $this->_convertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_PRE_ADD].'(ARCHIVE_ZIP_PARAM_PRE_ADD, $v_local_header);'); + if ($v_result == 0) { + // ----- Change the file status + $p_header['status'] = "skipped"; + $v_result = 1; + } + + // ----- Update the informations + // Only some fields can be modified + if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { + $p_header['stored_filename'] = $this->_tool_PathReduction($v_local_header['stored_filename']); + } + } + + // ----- Look for empty stored filename + if ($p_header['stored_filename'] == "") { + $p_header['status'] = "filtered"; + } + + // ----- Check the path length + if (strlen($p_header['stored_filename']) > 0xFF) { + $p_header['status'] = 'filename_too_long'; + } + + // ----- Look if no error, or file not skipped + if ($p_header['status'] == 'ok') { + + // ----- Look for a file + if (is_file($p_filename)) + { + // ----- Open the source file + if (($v_file = @fopen($p_filename, "rb")) == 0) { + $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); + return Archive_Zip::errorCode(); + } + + if ($p_params['no_compression']) { + // ----- Read the file content + $v_content_compressed = @fread($v_file, $p_header['size']); + + // ----- Calculate the CRC + $p_header['crc'] = crc32($v_content_compressed); + } + else { + // ----- Read the file content + $v_content = @fread($v_file, $p_header['size']); + + // ----- Calculate the CRC + $p_header['crc'] = crc32($v_content); + + // ----- Compress the file + $v_content_compressed = gzdeflate($v_content); + } + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content_compressed); + $p_header['compression'] = 8; + + // ----- Call the header generation + if (($v_result = $this->_writeFileHeader($p_header)) != 1) { + @fclose($v_file); + return $v_result; + } + + // ----- Write the compressed content + $v_binary_data = pack('a'.$p_header['compressed_size'], $v_content_compressed); + @fwrite($this->_zip_fd, $v_binary_data, $p_header['compressed_size']); + + // ----- Close the file + @fclose($v_file); + } + + // ----- Look for a directory + else + { + // ----- Set the file properties + $p_header['filename'] .= '/'; + $p_header['filename_len']++; + $p_header['size'] = 0; + $p_header['external'] = 0x41FF0010; // Value for a folder : to be checked + + // ----- Call the header generation + if (($v_result = $this->_writeFileHeader($p_header)) != 1) + { + return $v_result; + } + } + } + + // ----- Look for pre-add callback + if ( (isset($p_params[ARCHIVE_ZIP_PARAM_POST_ADD])) + && ($p_params[ARCHIVE_ZIP_PARAM_POST_ADD] != '')) { + + // ----- Generate a local information + $v_local_header = array(); + $this->_convertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_POST_ADD].'(ARCHIVE_ZIP_PARAM_POST_ADD, $v_local_header);'); + if ($v_result == 0) { + // ----- Ignored + $v_result = 1; + } + + // ----- Update the informations + // Nothing can be modified + } + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _writeFileHeader() + // Description : + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_writeFileHeader() + * + * { Description } + * + */ + function _writeFileHeader(&$p_header) + { + $v_result=1; + + // TBC + //for(reset($p_header); $key = key($p_header); next($p_header)) { + //} + + // ----- Store the offset position of the file + $p_header['offset'] = ftell($this->_zip_fd); + + // ----- Transform UNIX mtime to DOS format mdate/mtime + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; + $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; + + // ----- Packed data + $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, $p_header['version'], $p_header['flag'], + $p_header['compression'], $v_mtime, $v_mdate, + $p_header['crc'], $p_header['compressed_size'], $p_header['size'], + strlen($p_header['stored_filename']), $p_header['extra_len']); + + // ----- Write the first 148 bytes of the header in the archive + fputs($this->_zip_fd, $v_binary_data, 30); + + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) + { + fputs($this->_zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) + { + fputs($this->_zip_fd, $p_header['extra'], $p_header['extra_len']); + } + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _writeCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_writeCentralFileHeader() + * + * { Description } + * + */ + function _writeCentralFileHeader(&$p_header) + { + $v_result=1; + + // TBC + //for(reset($p_header); $key = key($p_header); next($p_header)) { + //} + + // ----- Transform UNIX mtime to DOS format mdate/mtime + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; + $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; + + // ----- Packed data + $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, $p_header['version'], $p_header['version_extracted'], + $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], + $p_header['compressed_size'], $p_header['size'], + strlen($p_header['stored_filename']), $p_header['extra_len'], $p_header['comment_len'], + $p_header['disk'], $p_header['internal'], $p_header['external'], $p_header['offset']); + + // ----- Write the 42 bytes of the header in the zip file + fputs($this->_zip_fd, $v_binary_data, 46); + + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) + { + fputs($this->_zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) + { + fputs($this->_zip_fd, $p_header['extra'], $p_header['extra_len']); + } + if ($p_header['comment_len'] != 0) + { + fputs($this->_zip_fd, $p_header['comment'], $p_header['comment_len']); + } + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _writeCentralHeader() + // Description : + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_writeCentralHeader() + * + * { Description } + * + */ + function _writeCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) + { + $v_result=1; + + // ----- Packed data + $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, $p_nb_entries, $p_size, $p_offset, strlen($p_comment)); + + // ----- Write the 22 bytes of the header in the zip file + fputs($this->_zip_fd, $v_binary_data, 22); + + // ----- Write the variable fields + if (strlen($p_comment) != 0) + { + fputs($this->_zip_fd, $p_comment, strlen($p_comment)); + } + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _list() + // Description : + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_list() + * + * { Description } + * + */ + function _list(&$p_list) + { + $v_result=1; + + // ----- Open the zip file + if (($this->_zip_fd = @fopen($this->_zipname, 'rb')) == 0) + { + // ----- Error log + $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->_zipname.'\' in binary read mode'); + + // ----- Return + return Archive_Zip::errorCode(); + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) + { + return $v_result; + } + + // ----- Go to beginning of Central Dir + @rewind($this->_zip_fd); + if (@fseek($this->_zip_fd, $v_central_dir['offset'])) + { + // ----- Error log + $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return Archive_Zip::errorCode(); + } + + // ----- Read each entry + for ($i=0; $i<$v_central_dir['entries']; $i++) + { + // ----- Read the file header + if (($v_result = $this->_readCentralFileHeader($v_header)) != 1) + { + return $v_result; + } + $v_header['index'] = $i; + + // ----- Get the only interesting attributes + $this->_convertHeader2FileInfo($v_header, $p_list[$i]); + unset($v_header); + } + + // ----- Close the zip file + $this->_closeFd(); + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _convertHeader2FileInfo() + // Description : + // This function takes the file informations from the central directory + // entries and extract the interesting parameters that will be given back. + // The resulting file infos are set in the array $p_info + // $p_info['filename'] : Filename with full path. Given by user (add), + // extracted in the filesystem (extract). + // $p_info['stored_filename'] : Stored filename in the archive. + // $p_info['size'] = Size of the file. + // $p_info['compressed_size'] = Compressed size of the file. + // $p_info['mtime'] = Last modification date of the file. + // $p_info['comment'] = Comment associated with the file. + // $p_info['folder'] = true/false : indicates if the entry is a folder or not. + // $p_info['status'] = status of the action on the file. + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_convertHeader2FileInfo() + * + * { Description } + * + */ + function _convertHeader2FileInfo($p_header, &$p_info) + { + $v_result=1; + + // ----- Get the interesting attributes + $p_info['filename'] = $p_header['filename']; + $p_info['stored_filename'] = $p_header['stored_filename']; + $p_info['size'] = $p_header['size']; + $p_info['compressed_size'] = $p_header['compressed_size']; + $p_info['mtime'] = $p_header['mtime']; + $p_info['comment'] = $p_header['comment']; + $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010); + $p_info['index'] = $p_header['index']; + $p_info['status'] = $p_header['status']; + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _extractByRule() + // Description : + // Extract a file or directory depending of rules (by index, by name, ...) + // Parameters : + // $p_file_list : An array where will be placed the properties of each + // extracted file + // $p_path : Path to add while writing the extracted files + // $p_remove_path : Path to remove (from the file memorized path) while writing the + // extracted files. If the path does not match the file path, + // the file is extracted with its memorized path. + // $p_remove_path does not apply to 'list' mode. + // $p_path and $p_remove_path are commulative. + // Return Values : + // 1 on success,0 or less on error (see error code list) + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_extractByRule() + * + * { Description } + * + */ + function _extractByRule(&$p_file_list, &$p_params) + { + $v_result=1; + + $p_path = $p_params['add_path']; + $p_remove_path = $p_params['remove_path']; + $p_remove_all_path = $p_params['remove_all_path']; + + // ----- Check the path + if (($p_path == "") + || ((substr($p_path, 0, 1) != "/") + && (substr($p_path, 0, 3) != "../") && (substr($p_path,1,2)!=":/"))) + $p_path = "./".$p_path; + + // ----- Reduce the path last (and duplicated) '/' + if (($p_path != "./") && ($p_path != "/")) { + // ----- Look for the path end '/' + while (substr($p_path, -1) == "/") { + $p_path = substr($p_path, 0, strlen($p_path)-1); + } + } + + // ----- Look for path to remove format (should end by /) + if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) { + $p_remove_path .= '/'; + } + $p_remove_path_size = strlen($p_remove_path); + + // ----- Open the zip file + if (($v_result = $this->_openFd('rb')) != 1) + { + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) + { + // ----- Close the zip file + $this->_closeFd(); + + return $v_result; + } + + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + + // ----- Read each entry + $j_start = 0; + for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) { + // ----- Read next Central dir entry + @rewind($this->_zip_fd); + if (@fseek($this->_zip_fd, $v_pos_entry)) { + $this->_closeFd(); + + $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, + 'Invalid archive size'); + + return Archive_Zip::errorCode(); + } + + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->_readCentralFileHeader($v_header)) != 1) { + $this->_closeFd(); + + return $v_result; + } + + // ----- Store the index + $v_header['index'] = $i; + + // ----- Store the file position + $v_pos_entry = ftell($this->_zip_fd); + + // ----- Look for the specific extract rules + $v_extract = false; + + // ----- Look for extract by name rule + if ( (isset($p_params[ARCHIVE_ZIP_PARAM_BY_NAME])) + && ($p_params[ARCHIVE_ZIP_PARAM_BY_NAME] != 0)) { + + // ----- Look if the filename is in the list + for ($j=0; + ($j strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) + && (substr($v_header['stored_filename'], 0, strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) { + $v_extract = true; + } + } + // ----- Look for a filename + elseif ($v_header['stored_filename'] == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]) { + $v_extract = true; + } + } + } + + // ----- Look for extract by ereg rule + else if ( (isset($p_params[ARCHIVE_ZIP_PARAM_BY_EREG])) + && ($p_params[ARCHIVE_ZIP_PARAM_BY_EREG] != "")) { + + if (ereg($p_params[ARCHIVE_ZIP_PARAM_BY_EREG], $v_header['stored_filename'])) { + $v_extract = true; + } + } + + // ----- Look for extract by preg rule + else if ( (isset($p_params[ARCHIVE_ZIP_PARAM_BY_PREG])) + && ($p_params[ARCHIVE_ZIP_PARAM_BY_PREG] != "")) { + + if (preg_match($p_params[ARCHIVE_ZIP_PARAM_BY_PREG], $v_header['stored_filename'])) { + $v_extract = true; + } + } + + // ----- Look for extract by index rule + else if ( (isset($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])) + && ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX] != 0)) { + + // ----- Look if the index is in the list + for ($j=$j_start; ($j=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']) && ($i<=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end'])) { + $v_extract = true; + } + if ($i>=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end']) { + $j_start = $j+1; + } + + if ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']>$i) { + break; + } + } + } + + // ----- Look for no rule, which means extract all the archive + else { + $v_extract = true; + } + + + // ----- Look for real extraction + if ($v_extract) + { + + // ----- Go to the file position + @rewind($this->_zip_fd); + if (@fseek($this->_zip_fd, $v_header['offset'])) + { + // ----- Close the zip file + $this->_closeFd(); + + // ----- Error log + $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return Archive_Zip::errorCode(); + } + + // ----- Look for extraction as string + if ($p_params[ARCHIVE_ZIP_PARAM_EXTRACT_AS_STRING]) { + + // ----- Extracting the file + if (($v_result = $this->_extractFileAsString($v_header, $v_string)) != 1) + { + // ----- Close the zip file + $this->_closeFd(); + + return $v_result; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->_convertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) + { + // ----- Close the zip file + $this->_closeFd(); + + return $v_result; + } + + // ----- Set the file content + $p_file_list[$v_nb_extracted]['content'] = $v_string; + + // ----- Next extracted file + $v_nb_extracted++; + } + else { + // ----- Extracting the file + if (($v_result = $this->_extractFile($v_header, $p_path, $p_remove_path, $p_remove_all_path, $p_params)) != 1) + { + // ----- Close the zip file + $this->_closeFd(); + + return $v_result; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->_convertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) + { + // ----- Close the zip file + $this->_closeFd(); + + return $v_result; + } + } + } + } + + // ----- Close the zip file + $this->_closeFd(); + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _extractFile() + // Description : + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_extractFile() + * + * { Description } + * + */ + function _extractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_params) + { + $v_result=1; + + // ----- Read the file header + if (($v_result = $this->_readFileHeader($v_header)) != 1) + { + // ----- Return + return $v_result; + } + + + // ----- Check that the file header is coherent with $p_entry info + // TBC + + // ----- Look for all path to remove + if ($p_remove_all_path == true) { + // ----- Get the basename of the path + $p_entry['filename'] = basename($p_entry['filename']); + } + + // ----- Look for path to remove + else if ($p_remove_path != "") + { + //if (strcmp($p_remove_path, $p_entry['filename'])==0) + if ($this->_tool_PathInclusion($p_remove_path, $p_entry['filename']) == 2) + { + + // ----- Change the file status + $p_entry['status'] = "filtered"; + + // ----- Return + return $v_result; + } + + $p_remove_path_size = strlen($p_remove_path); + if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) + { + + // ----- Remove the path + $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); + + } + } + + // ----- Add the path + if ($p_path != '') + { + $p_entry['filename'] = $p_path."/".$p_entry['filename']; + } + + // ----- Look for pre-extract callback + if ( (isset($p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT])) + && ($p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT] != '')) { + + // ----- Generate a local information + $v_local_header = array(); + $this->_convertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT].'(ARCHIVE_ZIP_PARAM_PRE_EXTRACT, $v_local_header);'); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } + + // ----- Trace + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Look for specific actions while the file exist + if (file_exists($p_entry['filename'])) + { + + // ----- Look if file is a directory + if (is_dir($p_entry['filename'])) + { + + // ----- Change the file status + $p_entry['status'] = "already_a_directory"; + + // ----- Return + //return $v_result; + } + // ----- Look if file is write protected + else if (!is_writeable($p_entry['filename'])) + { + + // ----- Change the file status + $p_entry['status'] = "write_protected"; + + // ----- Return + //return $v_result; + } + + // ----- Look if the extracted file is older + else if (filemtime($p_entry['filename']) > $p_entry['mtime']) + { + + // ----- Change the file status + $p_entry['status'] = "newer_exist"; + + // ----- Return + //return $v_result; + } + } + + // ----- Check the directory availability and create it if necessary + else { + if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/')) + $v_dir_to_check = $p_entry['filename']; + else if (!strstr($p_entry['filename'], "/")) + $v_dir_to_check = ""; + else + $v_dir_to_check = dirname($p_entry['filename']); + + if (($v_result = $this->_dirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) { + + // ----- Change the file status + $p_entry['status'] = "path_creation_fail"; + + // ----- Return + //return $v_result; + $v_result = 1; + } + } + } + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) + { + + // ----- Look for not compressed file + if ($p_entry['compressed_size'] == $p_entry['size']) + { + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) + { + + // ----- Change the file status + $p_entry['status'] = "write_error"; + + // ----- Return + return $v_result; + } + + + // ----- Read the file by ARCHIVE_ZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['compressed_size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->_zip_fd, $v_read_size); + $v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_binary_data, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Closing the destination file + fclose($v_dest_file); + + // ----- Change the file mtime + touch($p_entry['filename'], $p_entry['mtime']); + } + else + { + // ----- Trace + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + + // ----- Change the file status + $p_entry['status'] = "write_error"; + + return $v_result; + } + + + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->_zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + $v_file_content = gzinflate($v_buffer); + unset($v_buffer); + + // ----- Write the uncompressed data + @fwrite($v_dest_file, $v_file_content, $p_entry['size']); + unset($v_file_content); + + // ----- Closing the destination file + @fclose($v_dest_file); + + // ----- Change the file mtime + touch($p_entry['filename'], $p_entry['mtime']); + } + + // ----- Look for chmod option + if ( (isset($p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD])) + && ($p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD] != 0)) { + + // ----- Change the mode of the file + chmod($p_entry['filename'], $p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD]); + } + + } + } + + // ----- Look for post-extract callback + if ( (isset($p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT])) + && ($p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT] != '')) { + + // ----- Generate a local information + $v_local_header = array(); + $this->_convertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT].'(ARCHIVE_ZIP_PARAM_POST_EXTRACT, $v_local_header);'); + } + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _extractFileAsString() + // Description : + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_extractFileAsString() + * + * { Description } + * + */ + function _extractFileAsString(&$p_entry, &$p_string) + { + $v_result=1; + + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->_readFileHeader($v_header)) != 1) + { + // ----- Return + return $v_result; + } + + + // ----- Check that the file header is coherent with $p_entry info + // TBC + + // ----- Trace + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) + { + // ----- Look for not compressed file + if ($p_entry['compressed_size'] == $p_entry['size']) + { + // ----- Trace + + // ----- Reading the file + $p_string = fread($this->_zip_fd, $p_entry['compressed_size']); + } + else + { + // ----- Trace + + // ----- Reading the file + $v_data = fread($this->_zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + $p_string = gzinflate($v_data); + } + + // ----- Trace + } + else { + // TBC : error : can not extract a folder in a string + } + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _readFileHeader() + // Description : + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_readFileHeader() + * + * { Description } + * + */ + function _readFileHeader(&$p_header) + { + $v_result=1; + + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->_zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] != 0x04034b50) + { + + // ----- Error log + $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + + // ----- Return + return Archive_Zip::errorCode(); + } + + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->_zip_fd, 26); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 26) + { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; + + // ----- Error log + $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + + // ----- Return + return Archive_Zip::errorCode(); + } + + // ----- Extract the values + $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); + + // ----- Get filename + $p_header['filename'] = fread($this->_zip_fd, $v_data['filename_len']); + + // ----- Get extra_fields + if ($v_data['extra_len'] != 0) { + $p_header['extra'] = fread($this->_zip_fd, $v_data['extra_len']); + } + else { + $p_header['extra'] = ''; + } + + // ----- Extract properties + $p_header['compression'] = $v_data['compression']; + $p_header['size'] = $v_data['size']; + $p_header['compressed_size'] = $v_data['compressed_size']; + $p_header['crc'] = $v_data['crc']; + $p_header['flag'] = $v_data['flag']; + + // ----- Recuperate date in UNIX format + $p_header['mdate'] = $v_data['mdate']; + $p_header['mtime'] = $v_data['mtime']; + if ($p_header['mdate'] && $p_header['mtime']) + { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F)*2; + + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; + + // ----- Get UNIX date format + $p_header['mtime'] = mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + + } + else + { + $p_header['mtime'] = time(); + } + + // ----- Other informations + + // TBC + //for(reset($v_data); $key = key($v_data); next($v_data)) { + //} + + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + + // ----- Set the status field + $p_header['status'] = "ok"; + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _readCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_readCentralFileHeader() + * + * { Description } + * + */ + function _readCentralFileHeader(&$p_header) + { + $v_result=1; + + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->_zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] != 0x02014b50) + { + + // ----- Error log + $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + + // ----- Return + return Archive_Zip::errorCode(); + } + + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->_zip_fd, 42); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 42) + { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; + + // ----- Error log + $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + + // ----- Return + return Archive_Zip::errorCode(); + } + + // ----- Extract the values + $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data); + + // ----- Get filename + if ($p_header['filename_len'] != 0) + $p_header['filename'] = fread($this->_zip_fd, $p_header['filename_len']); + else + $p_header['filename'] = ''; + + // ----- Get extra + if ($p_header['extra_len'] != 0) + $p_header['extra'] = fread($this->_zip_fd, $p_header['extra_len']); + else + $p_header['extra'] = ''; + + // ----- Get comment + if ($p_header['comment_len'] != 0) + $p_header['comment'] = fread($this->_zip_fd, $p_header['comment_len']); + else + $p_header['comment'] = ''; + + // ----- Extract properties + + // ----- Recuperate date in UNIX format + if ($p_header['mdate'] && $p_header['mtime']) + { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F)*2; + + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; + + // ----- Get UNIX date format + $p_header['mtime'] = mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + + } + else + { + $p_header['mtime'] = time(); + } + + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + + // ----- Set default status to ok + $p_header['status'] = 'ok'; + + // ----- Look if it is a directory + if (substr($p_header['filename'], -1) == '/') + { + $p_header['external'] = 0x41FF0010; + } + + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _readEndCentralDir() + // Description : + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_readEndCentralDir() + * + * { Description } + * + */ + function _readEndCentralDir(&$p_central_dir) + { + $v_result=1; + + // ----- Go to the end of the zip file + $v_size = filesize($this->_zipname); + @fseek($this->_zip_fd, $v_size); + if (@ftell($this->_zip_fd) != $v_size) { + $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, + 'Unable to go to the end of the archive \'' + .$this->_zipname.'\''); + return Archive_Zip::errorCode(); + } + + // ----- First try : look if this is an archive with no commentaries + // (most of the time) + // in this case the end of central dir is at 22 bytes of the file end + $v_found = 0; + if ($v_size > 26) { + @fseek($this->_zip_fd, $v_size-22); + if (($v_pos = @ftell($this->_zip_fd)) != ($v_size-22)) { + $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, + 'Unable to seek back to the middle of the archive \'' + .$this->_zipname.'\''); + return Archive_Zip::errorCode(); + } + + // ----- Read for bytes + $v_binary_data = @fread($this->_zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] == 0x06054b50) { + $v_found = 1; + } + + $v_pos = ftell($this->_zip_fd); + } + + // ----- Go back to the maximum possible size of the Central Dir End Record + if (!$v_found) { + $v_maximum_size = 65557; // 0xFFFF + 22; + if ($v_maximum_size > $v_size) + $v_maximum_size = $v_size; + @fseek($this->_zip_fd, $v_size-$v_maximum_size); + if (@ftell($this->_zip_fd) != ($v_size-$v_maximum_size)) { + $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, + 'Unable to seek back to the middle of the archive \'' + .$this->_zipname.'\''); + return Archive_Zip::errorCode(); + } + + // ----- Read byte per byte in order to find the signature + $v_pos = ftell($this->_zip_fd); + $v_bytes = 0x00000000; + while ($v_pos < $v_size) { + // ----- Read a byte + $v_byte = @fread($this->_zip_fd, 1); + + // ----- Add the byte + $v_bytes = ($v_bytes << 8) | Ord($v_byte); + + // ----- Compare the bytes + if ($v_bytes == 0x504b0506) { + $v_pos++; + break; + } + + $v_pos++; + } + + // ----- Look if not found end of central dir + if ($v_pos == $v_size) { + $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, + "Unable to find End of Central Dir Record signature"); + return Archive_Zip::errorCode(); + } + } + + // ----- Read the first 18 bytes of the header + $v_binary_data = fread($this->_zip_fd, 18); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 18) { + $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, + "Invalid End of Central Dir Record size : " + .strlen($v_binary_data)); + return Archive_Zip::errorCode(); + } + + // ----- Extract the values + $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); + + // ----- Check the global size + if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { + $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, + "Fail to find the right signature"); + return Archive_Zip::errorCode(); + } + + // ----- Get comment + if ($v_data['comment_size'] != 0) + $p_central_dir['comment'] = fread($this->_zip_fd, $v_data['comment_size']); + else + $p_central_dir['comment'] = ''; + + $p_central_dir['entries'] = $v_data['entries']; + $p_central_dir['disk_entries'] = $v_data['disk_entries']; + $p_central_dir['offset'] = $v_data['offset']; + $p_central_dir['size'] = $v_data['size']; + $p_central_dir['disk'] = $v_data['disk']; + $p_central_dir['disk_start'] = $v_data['disk_start']; + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _deleteByRule() + // Description : + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_deleteByRule() + * + * { Description } + * + */ + function _deleteByRule(&$p_result_list, &$p_params) + { + $v_result=1; + $v_list_detail = array(); + + // ----- Open the zip file + if (($v_result=$this->_openFd('rb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) + { + $this->_closeFd(); + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->_zip_fd); + + // ----- Scan all the files + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + @rewind($this->_zip_fd); + if (@fseek($this->_zip_fd, $v_pos_entry)) { + // ----- Clean + $this->_closeFd(); + + $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, + 'Invalid archive size'); + return Archive_Zip::errorCode(); + } + + // ----- Read each entry + $v_header_list = array(); + $j_start = 0; + for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) { + + // ----- Read the file header + $v_header_list[$v_nb_extracted] = array(); + $v_result + = $this->_readCentralFileHeader($v_header_list[$v_nb_extracted]); + if ($v_result != 1) { + // ----- Clean + $this->_closeFd(); + + return $v_result; + } + + // ----- Store the index + $v_header_list[$v_nb_extracted]['index'] = $i; + + // ----- Look for the specific extract rules + $v_found = false; + + // ----- Look for extract by name rule + if ( (isset($p_params[ARCHIVE_ZIP_PARAM_BY_NAME])) + && ($p_params[ARCHIVE_ZIP_PARAM_BY_NAME] != 0)) { + + // ----- Look if the filename is in the list + for ($j=0; + ($j strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) + && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) { + $v_found = true; + } + elseif ( (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */ + && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) { + $v_found = true; + } + } + // ----- Look for a filename + elseif ($v_header_list[$v_nb_extracted]['stored_filename'] + == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]) { + $v_found = true; + } + } + } + + // ----- Look for extract by ereg rule + else if ( (isset($p_params[ARCHIVE_ZIP_PARAM_BY_EREG])) + && ($p_params[ARCHIVE_ZIP_PARAM_BY_EREG] != "")) { + + if (ereg($p_params[ARCHIVE_ZIP_PARAM_BY_EREG], + $v_header_list[$v_nb_extracted]['stored_filename'])) { + $v_found = true; + } + } + + // ----- Look for extract by preg rule + else if ( (isset($p_params[ARCHIVE_ZIP_PARAM_BY_PREG])) + && ($p_params[ARCHIVE_ZIP_PARAM_BY_PREG] != "")) { + + if (preg_match($p_params[ARCHIVE_ZIP_PARAM_BY_PREG], + $v_header_list[$v_nb_extracted]['stored_filename'])) { + $v_found = true; + } + } + + // ----- Look for extract by index rule + else if ( (isset($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])) + && ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX] != 0)) { + + // ----- Look if the index is in the list + for ($j=$j_start; + ($j=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']) + && ($i<=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end'])) { + $v_found = true; + } + if ($i>=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end']) { + $j_start = $j+1; + } + + if ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']>$i) { + break; + } + } + } + + // ----- Look for deletion + if ($v_found) { + unset($v_header_list[$v_nb_extracted]); + } + else { + $v_nb_extracted++; + } + } + + // ----- Look if something need to be deleted + if ($v_nb_extracted > 0) { + + // ----- Creates a temporay file + $v_zip_temp_name = ARCHIVE_ZIP_TEMPORARY_DIR.uniqid('archive_zip-') + .'.tmp'; + + // ----- Creates a temporary zip archive + $v_temp_zip = new Archive_Zip($v_zip_temp_name); + + // ----- Open the temporary zip file in write mode + if (($v_result = $v_temp_zip->_openFd('wb')) != 1) { + $this->_closeFd(); + + // ----- Return + return $v_result; + } + + // ----- Look which file need to be kept + for ($i=0; $i_zip_fd); + if (@fseek($this->_zip_fd, $v_header_list[$i]['offset'])) { + // ----- Clean + $this->_closeFd(); + $v_temp_zip->_closeFd(); + @unlink($v_zip_temp_name); + + $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, + 'Invalid archive size'); + return Archive_Zip::errorCode(); + } + + // ----- Read the file header + if (($v_result = $this->_readFileHeader($v_header_list[$i])) != 1) { + // ----- Clean + $this->_closeFd(); + $v_temp_zip->_closeFd(); + @unlink($v_zip_temp_name); + + return $v_result; + } + + // ----- Write the file header + $v_result = $v_temp_zip->_writeFileHeader($v_header_list[$i]); + if ($v_result != 1) { + // ----- Clean + $this->_closeFd(); + $v_temp_zip->_closeFd(); + @unlink($v_zip_temp_name); + + return $v_result; + } + + // ----- Read/write the data block + $v_result = $this->_tool_CopyBlock($this->_zip_fd, + $v_temp_zip->_zip_fd, + $v_header_list[$i]['compressed_size']); + if ($v_result != 1) { + // ----- Clean + $this->_closeFd(); + $v_temp_zip->_closeFd(); + @unlink($v_zip_temp_name); + + return $v_result; + } + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($v_temp_zip->_zip_fd); + + // ----- Re-Create the Central Dir files header + for ($i=0; $i_writeCentralFileHeader($v_header_list[$i]); + if ($v_result != 1) { + // ----- Clean + $v_temp_zip->_closeFd(); + $this->_closeFd(); + @unlink($v_zip_temp_name); + + return $v_result; + } + + // ----- Transform the header to a 'usable' info + $v_temp_zip->_convertHeader2FileInfo($v_header_list[$i], + $p_result_list[$i]); + } + + + // ----- Zip file comment + $v_comment = ''; + + // ----- Calculate the size of the central header + $v_size = @ftell($v_temp_zip->_zip_fd)-$v_offset; + + // ----- Create the central dir footer + $v_result = $v_temp_zip->_writeCentralHeader(sizeof($v_header_list), + $v_size, $v_offset, + $v_comment); + if ($v_result != 1) { + // ----- Clean + unset($v_header_list); + $v_temp_zip->_closeFd(); + $this->_closeFd(); + @unlink($v_zip_temp_name); + + return $v_result; + } + + // ----- Close + $v_temp_zip->_closeFd(); + $this->_closeFd(); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->_zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->_zipname); + $this->_tool_Rename($v_zip_temp_name, $this->_zipname); + + // ----- Destroy the temporary archive + unset($v_temp_zip); + } + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _dirCheck() + // Description : + // Check if a directory exists, if not it creates it and all the parents directory + // which may be useful. + // Parameters : + // $p_dir : Directory path to check. + // Return Values : + // 1 : OK + // -1 : Unable to create directory + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_dirCheck() + * + * { Description } + * + * @param [type] $p_is_dir + */ + function _dirCheck($p_dir, $p_is_dir=false) + { + $v_result = 1; + + // ----- Remove the final '/' + if (($p_is_dir) && (substr($p_dir, -1)=='/')) { + $p_dir = substr($p_dir, 0, strlen($p_dir)-1); + } + + // ----- Check the directory availability + if ((is_dir($p_dir)) || ($p_dir == "")) { + return 1; + } + + // ----- Extract parent directory + $p_parent_dir = dirname($p_dir); + + // ----- Just a check + if ($p_parent_dir != $p_dir) { + // ----- Look for parent directory + if ($p_parent_dir != "") { + if (($v_result = $this->_dirCheck($p_parent_dir)) != 1) { + return $v_result; + } + } + } + + // ----- Create the directory + if (!@mkdir($p_dir, 0777)) { + $this->_errorLog(ARCHIVE_ZIP_ERR_DIR_CREATE_FAIL, + "Unable to create directory '$p_dir'"); + return Archive_Zip::errorCode(); + } + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _merge() + // Description : + // If $p_archive_to_add does not exist, the function exit with a success result. + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_merge() + * + * { Description } + * + */ + function _merge(&$p_archive_to_add) + { + $v_result=1; + + // ----- Look if the archive_to_add exists + if (!is_file($p_archive_to_add->_zipname)) { + // ----- Nothing to merge, so merge is a success + return 1; + } + + // ----- Look if the archive exists + if (!is_file($this->_zipname)) { + // ----- Do a duplicate + $v_result = $this->_duplicate($p_archive_to_add->_zipname); + + return $v_result; + } + + // ----- Open the zip file + if (($v_result=$this->_openFd('rb')) != 1) { + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) { + $this->_closeFd(); + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->_zip_fd); + + // ----- Open the archive_to_add file + if (($v_result=$p_archive_to_add->_openFd('rb')) != 1) { + $this->_closeFd(); + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir_to_add = array(); + $v_result = $p_archive_to_add->_readEndCentralDir($v_central_dir_to_add); + if ($v_result != 1) { + $this->_closeFd(); + $p_archive_to_add->_closeFd(); + return $v_result; + } + + // ----- Go to beginning of File + @rewind($p_archive_to_add->_zip_fd); + + // ----- Creates a temporay file + $v_zip_temp_name = ARCHIVE_ZIP_TEMPORARY_DIR.uniqid('archive_zip-').'.tmp'; + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) { + $this->_closeFd(); + $p_archive_to_add->_closeFd(); + $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, + 'Unable to open temporary file \'' + .$v_zip_temp_name.'\' in binary write mode'); + return Archive_Zip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the + // central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) { + $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE + ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->_zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Copy the files from the archive_to_add into the temporary file + $v_size = $v_central_dir_to_add['offset']; + while ($v_size != 0) { + $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE + ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); + $v_buffer = fread($p_archive_to_add->_zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($v_zip_temp_fd); + + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) { + $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE + ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->_zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Copy the block of file headers from the archive_to_add + $v_size = $v_central_dir_to_add['size']; + while ($v_size != 0) { + $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE + ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_archive_to_add->_zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Zip file comment + // TBC : I should merge the two comments + $v_comment = ''; + + // ----- Calculate the size of the (new) central header + $v_size = @ftell($v_zip_temp_fd)-$v_offset; + + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive fd + $v_swap = $this->_zip_fd; + $this->_zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Create the central dir footer + if (($v_result = $this->_writeCentralHeader($v_central_dir['entries'] + +$v_central_dir_to_add['entries'], + $v_size, $v_offset, + $v_comment)) != 1) { + $this->_closeFd(); + $p_archive_to_add->_closeFd(); + @fclose($v_zip_temp_fd); + $this->_zip_fd = null; + + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } + + // ----- Swap back the file descriptor + $v_swap = $this->_zip_fd; + $this->_zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Close + $this->_closeFd(); + $p_archive_to_add->_closeFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->_zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->_zipname); + $this->_tool_Rename($v_zip_temp_name, $this->_zipname); + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _duplicate() + // Description : + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_duplicate() + * + * { Description } + * + */ + function _duplicate($p_archive_filename) + { + $v_result=1; + + // ----- Look if the $p_archive_filename exists + if (!is_file($p_archive_filename)) { + + // ----- Nothing to duplicate, so duplicate is a success. + $v_result = 1; + + // ----- Return + return $v_result; + } + + // ----- Open the zip file + if (($v_result=$this->_openFd('wb')) != 1) { + // ----- Return + return $v_result; + } + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) { + $this->_closeFd(); + $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, + 'Unable to open archive file \'' + .$p_archive_filename.'\' in binary write mode'); + return Archive_Zip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the + // central dir + $v_size = filesize($p_archive_filename); + while ($v_size != 0) { + $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE + ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); + $v_buffer = fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->_zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close + $this->_closeFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + return $v_result; + } + // --------------------------------------------------------------------------- + + /** + * Archive_Zip::_check_parameters() + * + * { Description } + * + * @param integer $p_error_code + * @param string $p_error_string + */ + function _check_parameters(&$p_params, $p_default) + { + + // ----- Check that param is an array + if (!is_array($p_params)) { + $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, + 'Unsupported parameter, waiting for an array'); + return Archive_Zip::errorCode(); + } + + // ----- Check that all the params are valid + for (reset($p_params); list($v_key, $v_value) = each($p_params); ) { + if (!isset($p_default[$v_key])) { + $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, + 'Unsupported parameter with key \''.$v_key.'\''); + + return Archive_Zip::errorCode(); + } + } + + // ----- Set the default values + for (reset($p_default); list($v_key, $v_value) = each($p_default); ) { + if (!isset($p_params[$v_key])) { + $p_params[$v_key] = $p_default[$v_key]; + } + } + + // ----- Check specific parameters + $v_callback_list = array ('callback_pre_add','callback_post_add', + 'callback_pre_extract','callback_post_extract'); + for ($i=0; $i_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAM_VALUE, + "Callback '".$p_params[$v_key] + ."()' is not an existing function for " + ."parameter '".$v_key."'"); + return Archive_Zip::errorCode(); + } + } + } + + return(1); + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _errorLog() + // Description : + // Parameters : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_errorLog() + * + * { Description } + * + * @param integer $p_error_code + * @param string $p_error_string + */ + function _errorLog($p_error_code=0, $p_error_string='') + { + $this->_error_code = $p_error_code; + $this->_error_string = $p_error_string; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : _errorReset() + // Description : + // Parameters : + // --------------------------------------------------------------------------- + /** + * Archive_Zip::_errorReset() + * + * { Description } + * + */ + function _errorReset() + { + $this->_error_code = 1; + $this->_error_string = ''; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : $this->_tool_PathReduction() + // Description : + // Parameters : + // Return Values : + // --------------------------------------------------------------------------- + /** + * _tool_PathReduction() + * + * { Description } + * + */ + function _tool_PathReduction($p_dir) + { + $v_result = ""; + + // ----- Look for not empty path + if ($p_dir != "") + { + // ----- Explode path by directory names + $v_list = explode("/", $p_dir); + + // ----- Study directories from last to first + for ($i=sizeof($v_list)-1; $i>=0; $i--) + { + // ----- Look for current path + if ($v_list[$i] == ".") + { + // ----- Ignore this directory + // Should be the first $i=0, but no check is done + } + else if ($v_list[$i] == "..") + { + // ----- Ignore it and ignore the $i-1 + $i--; + } + else if (($v_list[$i] == "") && ($i!=(sizeof($v_list)-1)) && ($i!=0)) + { + // ----- Ignore only the double '//' in path, + // but not the first and last '/' + } + else + { + $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:""); + } + } + } + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : $this->_tool_PathInclusion() + // Description : + // This function indicates if the path $p_path is under the $p_dir tree. Or, + // said in an other way, if the file or sub-dir $p_path is inside the dir + // $p_dir. + // The function indicates also if the path is exactly the same as the dir. + // This function supports path with duplicated '/' like '//', but does not + // support '.' or '..' statements. + // Parameters : + // Return Values : + // 0 if $p_path is not inside directory $p_dir + // 1 if $p_path is inside directory $p_dir + // 2 if $p_path is exactly the same as $p_dir + // --------------------------------------------------------------------------- + /** + * _tool_PathInclusion() + * + * { Description } + * + */ + function _tool_PathInclusion($p_dir, $p_path) + { + $v_result = 1; + + // ----- Explode dir and path by directory separator + $v_list_dir = explode("/", $p_dir); + $v_list_dir_size = sizeof($v_list_dir); + $v_list_path = explode("/", $p_path); + $v_list_path_size = sizeof($v_list_path); + + // ----- Study directories paths + $i = 0; + $j = 0; + while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) { + + // ----- Look for empty dir (path reduction) + if ($v_list_dir[$i] == '') { + $i++; + continue; + } + if ($v_list_path[$j] == '') { + $j++; + continue; + } + + // ----- Compare the items + if ( ($v_list_dir[$i] != $v_list_path[$j]) + && ($v_list_dir[$i] != '') + && ( $v_list_path[$j] != '')) { + $v_result = 0; + } + + // ----- Next items + $i++; + $j++; + } + + // ----- Look if everything seems to be the same + if ($v_result) { + // ----- Skip all the empty items + while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++; + while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++; + + if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { + // ----- There are exactly the same + $v_result = 2; + } + else if ($i < $v_list_dir_size) { + // ----- The path is shorter than the dir + $v_result = 0; + } + } + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : $this->_tool_CopyBlock() + // Description : + // Parameters : + // $p_mode : read/write compression mode + // 0 : src & dest normal + // 1 : src gzip, dest normal + // 2 : src normal, dest gzip + // 3 : src & dest gzip + // Return Values : + // --------------------------------------------------------------------------- + /** + * _tool_CopyBlock() + * + * { Description } + * + * @param integer $p_mode + */ + function _tool_CopyBlock($p_src, $p_dest, $p_size, $p_mode=0) + { + $v_result = 1; + + if ($p_mode==0) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE + ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==1) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE + ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==2) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE + ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==3) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE + ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : $this->_tool_Rename() + // Description : + // This function tries to do a simple rename() function. If it fails, it + // tries to copy the $p_src file in a new $p_dest file and then unlink the + // first one. + // Parameters : + // $p_src : Old filename + // $p_dest : New filename + // Return Values : + // 1 on success, 0 on failure. + // --------------------------------------------------------------------------- + /** + * _tool_Rename() + * + * { Description } + * + */ + function _tool_Rename($p_src, $p_dest) + { + $v_result = 1; + + // ----- Try to rename the files + if (!@rename($p_src, $p_dest)) { + + // ----- Try to copy & unlink the src + if (!@copy($p_src, $p_dest)) { + $v_result = 0; + } + else if (!@unlink($p_src)) { + $v_result = 0; + } + } + + // ----- Return + return $v_result; + } + // --------------------------------------------------------------------------- + + // --------------------------------------------------------------------------- + // Function : $this->_tool_TranslateWinPath() + // Description : + // Translate windows path by replacing '\' by '/' and optionally removing + // drive letter. + // Parameters : + // $p_path : path to translate. + // $p_remove_disk_letter : true | false + // Return Values : + // The path translated. + // --------------------------------------------------------------------------- + /** + * _tool_TranslateWinPath() + * + * { Description } + * + * @param [type] $p_remove_disk_letter + */ + function _tool_TranslateWinPath($p_path, $p_remove_disk_letter=true) + { + if (stristr(php_uname(), 'windows')) { + // ----- Look for potential disk letter + if ( ($p_remove_disk_letter) + && (($v_position = strpos($p_path, ':')) != false)) { + $p_path = substr($p_path, $v_position+1); + } + // ----- Change potential windows directory separator + if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { + $p_path = strtr($p_path, '\\', '/'); + } + } + return $p_path; + } + // --------------------------------------------------------------------------- + + } + // End of class + +?> diff --git a/buildscripts/phing/classes/phing/listener/AnsiColorLogger.php b/buildscripts/phing/classes/phing/listener/AnsiColorLogger.php new file mode 100644 index 00000000..00b0a7a9 --- /dev/null +++ b/buildscripts/phing/classes/phing/listener/AnsiColorLogger.php @@ -0,0 +1,231 @@ +. + */ + +require_once 'phing/listener/DefaultLogger.php'; +include_once 'phing/system/util/Properties.php'; + +/** + * Uses ANSI Color Code Sequences to colorize messages + * sent to the console. + * + * If used with the -logfile option, the output file + * will contain all the necessary escape codes to + * display the text in colorized mode when displayed + * in the console using applications like cat, more, + * etc. + * + * This is designed to work on terminals that support ANSI + * color codes. It works on XTerm, ETerm, Mindterm, etc. + * It also works on Win9x (with ANSI.SYS loaded.) + * + * NOTE: + * It doesn't work on WinNT's COMMAND.COM even with + * ANSI.SYS loaded. + * + * The default colors used for differentiating + * the message levels can be changed by editing the + * /org/apache/tools/ant/listener/defaults.properties + * file. + * This file contains 5 key/value pairs: + * AnsiColorLogger.ERROR_COLOR=2;31 + * AnsiColorLogger.WARNING_COLOR=2;35 + * AnsiColorLogger.INFO_COLOR=2;36 + * AnsiColorLogger.VERBOSE_COLOR=2;32 + * AnsiColorLogger.DEBUG_COLOR=2;34 + * + * Another option is to pass a system variable named + * ant.logger.defaults, with value set to the path of + * the file that contains user defined Ansi Color + * Codes, to the java command using -D option. + * + * To change these colors use the following chart: + * + * ANSI COLOR LOGGER CONFIGURATION + * + * Format for AnsiColorLogger.*= + * Attribute;Foreground;Background + * + * Attribute is one of the following: + * 0 -> Reset All Attributes (return to normal mode) + * 1 -> Bright (Usually turns on BOLD) + * 2 -> Dim + * 3 -> Underline + * 5 -> link + * 7 -> Reverse + * 8 -> Hidden + * + * Foreground is one of the following: + * 30 -> Black + * 31 -> Red + * 32 -> Green + * 33 -> Yellow + * 34 -> Blue + * 35 -> Magenta + * 36 -> Cyan + * 37 -> White + * + * Background is one of the following: + * 40 -> Black + * 41 -> Red + * 42 -> Green + * 43 -> Yellow + * 44 -> Blue + * 45 -> Magenta + * 46 -> Cyan + * 47 -> White + * + * @author Hans Lellelid (Phing) + * @author Magesh Umasankar (Ant) + * @package phing.listener + * @version $Revision: 1.13 $ + */ +final class AnsiColorLogger extends DefaultLogger { + + const ATTR_NORMAL = 0; + const ATTR_BRIGHT = 1; + const ATTR_DIM = 2; + const ATTR_UNDERLINE = 3; + const ATTR_BLINK = 5; + const ATTR_REVERSE = 7; + const ATTR_HIDDEN = 8; + + const FG_BLACK = 30; + const FG_RED = 31; + const FG_GREEN = 32; + const FG_YELLOW = 33; + const FG_BLUE = 34; + const FG_MAGENTA = 35; + const FG_CYAN = 36; + const FG_WHITE = 37; + + const BG_BLACK = 40; + const BG_RED = 41; + const BG_GREEN = 42; + const BG_YELLOW = 44; + const BG_BLUE = 44; + const BG_MAGENTA = 45; + const BG_CYAN = 46; + const BG_WHITE = 47; + + const PREFIX = "\x1b["; + const SUFFIX = "m"; + const SEPARATOR = ';'; + const END_COLOR = "\x1b[m"; // self::PREFIX . self::SUFFIX; + + private $errColor; + private $warnColor; + private $infoColor; + private $verboseColor; + private $debugColor; + + private $colorsSet = false; + + /** + * Construct new AnsiColorLogger + * Perform initializations that cannot be done in var declarations. + */ + public function __construct() { + parent::__construct(); + $this->errColor = self::PREFIX . self::ATTR_DIM . self::SEPARATOR . self::FG_RED . self::SUFFIX; + $this->warnColor = self::PREFIX . self::ATTR_DIM . self::SEPARATOR . self::FG_MAGENTA . self::SUFFIX; + $this->infoColor = self::PREFIX . self::ATTR_DIM . self::SEPARATOR . self::FG_CYAN . self::SUFFIX; + $this->verboseColor = self::PREFIX . self::ATTR_DIM . self::SEPARATOR . self::FG_GREEN . self::SUFFIX; + $this->debugColor = self::PREFIX . self::ATTR_DIM . self::SEPARATOR . self::FG_BLUE . self::SUFFIX; + } + + /** + * Set the colors to use from a property file specified by the + * special ant property ant.logger.defaults + */ + private final function setColors() { + + $userColorFile = Phing::getProperty("phing.logger.defaults"); + $systemColorFile = new PhingFile(Phing::getResourcePath("phing/listener/defaults.properties")); + + $in = null; + + try { + $prop = new Properties(); + + if ($userColorFile !== null) { + $prop->load($userColorFile); + } else { + $prop->load($systemColorFile); + } + + $err = $prop->getProperty("AnsiColorLogger.ERROR_COLOR"); + $warn = $prop->getProperty("AnsiColorLogger.WARNING_COLOR"); + $info = $prop->getProperty("AnsiColorLogger.INFO_COLOR"); + $verbose = $prop->getProperty("AnsiColorLogger.VERBOSE_COLOR"); + $debug = $prop->getProperty("AnsiColorLogger.DEBUG_COLOR"); + if ($err !== null) { + $errColor = self::PREFIX . $err . self::SUFFIX; + } + if ($warn !== null) { + $warnColor = self::PREFIX . $warn . self::SUFFIX; + } + if ($info !== null) { + $infoColor = self::PREFIX . $info . self::SUFFIX; + } + if ($verbose !== null) { + $verboseColor = self::PREFIX . $verbose . self::SUFFIX; + } + if ($debug !== null) { + $debugColor = self::PREFIX . $debug . self::SUFFIX; + } + } catch (IOException $ioe) { + //Ignore exception - we will use the defaults. + } + } + + /** + * @see DefaultLogger#printMessage + */ + protected final function printMessage($message, $priority) { + + if ($message !== null) { + + if (!$this->colorsSet) { + $this->setColors(); + $this->colorsSet = true; + } + + switch ($priority) { + case PROJECT_MSG_ERR: + $message = $this->errColor . $message . self::END_COLOR; + break; + case PROJECT_MSG_WARN: + $message = $this->warnColor . $message . self::END_COLOR; + break; + case PROJECT_MSG_INFO: + $message = $this->infoColor . $message . self::END_COLOR; + break; + case PROJECT_MSG_VERBOSE: + $message = $this->verboseColor . $message . self::END_COLOR; + break; + case PROJECT_MSG_DEBUG: + $message = $this->debugColor . $message . self::END_COLOR; + break; + } + print($message."\n"); + } + } +} diff --git a/buildscripts/phing/classes/phing/listener/BuildLogger.php b/buildscripts/phing/classes/phing/listener/BuildLogger.php new file mode 100644 index 00000000..d1c5fcb6 --- /dev/null +++ b/buildscripts/phing/classes/phing/listener/BuildLogger.php @@ -0,0 +1,42 @@ +. + */ + + require_once 'phing/BuildListener.php'; + /** + * Interface used by Phing Ant to log the build output. + * + * @author Michiel Rook + * @version $Id: BuildLogger.php,v 1.3 2005/02/11 10:51:21 mrook Exp $ + * @package phing.listener + */ + interface BuildLogger extends BuildListener + { + /** + * Sets the highest level of message this logger should respond to. + * + * Only messages with a message level lower than or equal to the + * given level should be written to the log. + * + * @param int the logging level for the logger. + */ + function setMessageOutputLevel($level); + }; +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/listener/DefaultLogger.php b/buildscripts/phing/classes/phing/listener/DefaultLogger.php new file mode 100644 index 00000000..c7387592 --- /dev/null +++ b/buildscripts/phing/classes/phing/listener/DefaultLogger.php @@ -0,0 +1,233 @@ +. + */ + +require_once 'phing/BuildListener.php'; +include_once 'phing/BuildEvent.php'; + +/** + * Writes a build event to the console. + * + * Currently, it only writes which targets are being executed, and + * any messages that get logged. + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.11 $ $Date: 2005/08/25 19:33:43 $ + * @see BuildEvent + * @package phing.listener + */ +class DefaultLogger implements BuildListener { + + /** + * Size of the left column in output. The default char width is 12. + * @var int + */ + const LEFT_COLUMN_SIZE = 12; + + /** + * The message output level that should be used. The default is + * PROJECT_MSG_VERBOSE. + * @var int + */ + protected $msgOutputLevel = PROJECT_MSG_ERR; + + /** + * Time that the build started + * @var int + */ + protected $startTime; + + /** + * Char that should be used to seperate lines. Default is the system + * property line.seperator. + * @var string + */ + protected $lSep; + + /** + * Construct a new default logger. + */ + public function __construct() { + $this->lSep = Phing::getProperty("line.separator"); + } + + /** + * Set the msgOutputLevel this logger is to respond to. + * + * Only messages with a message level lower than or equal to the given + * level are output to the log. + * + *

                                                Constants for the message levels are in Project.php. The order of + * the levels, from least to most verbose, is: + * + *

                                                  + *
                                                • PROJECT_MSG_ERR
                                                • + *
                                                • PROJECT_MSG_WARN
                                                • + *
                                                • PROJECT_MSG_INFO
                                                • + *
                                                • PROJECT_MSG_VERBOSE
                                                • + *
                                                • PROJECT_MSG_DEBUG
                                                • + *
                                                + * + * The default message level for DefaultLogger is PROJECT_MSG_ERR. + * + * @param integer the logging level for the logger. + * @access public + */ + function setMessageOutputLevel($level) { + $this->msgOutputLevel = (int) $level; + } + + /** + * Sets the start-time when the build started. Used for calculating + * the build-time. + * + * @param object The BuildEvent + * @access public + */ + + function buildStarted(BuildEvent $event) { + $this->startTime = Phing::currentTimeMillis(); + if ($this->msgOutputLevel >= PROJECT_MSG_INFO) { + $this->printMessage("Buildfile: ".$event->getProject()->getProperty("phing.file"), PROJECT_MSG_INFO); + } + } + + /** + * Prints whether the build succeeded or failed, and any errors that + * occured during the build. Also outputs the total build-time. + * + * @param object The BuildEvent + * @access public + * @see BuildEvent::getException() + */ + function buildFinished(BuildEvent $event) { + $error = $event->getException(); + if ($error === null) { + print($this->lSep . "BUILD FINISHED" . $this->lSep); + } else { + print($this->lSep . "BUILD FAILED" . $this->lSep); + if (PROJECT_MSG_VERBOSE <= $this->msgOutputLevel || !($error instanceof BuildException)) { + print($error->__toString().$this->lSep); + } else { + print($error->getMessage()); + } + } + print($this->lSep . "Total time: " .$this->_formatTime(Phing::currentTimeMillis() - $this->startTime) . $this->lSep); + } + + /** + * Prints the current target name + * + * @param object The BuildEvent + * @access public + * @see BuildEvent::getTarget() + */ + function targetStarted(BuildEvent $event) { + if (PROJECT_MSG_INFO <= $this->msgOutputLevel) { + print($this->lSep . $event->getProject()->getName() . ' > ' . $event->getTarget()->getName() . ':' . $this->lSep); + } + } + + /** + * Fired when a target has finished. We don't need specific action on this + * event. So the methods are empty. + * + * @param object The BuildEvent + * @access public + * @see BuildEvent::getException() + */ + function targetFinished(BuildEvent $event) {} + + /** + * Fired when a task is started. We don't need specific action on this + * event. So the methods are empty. + * + * @param object The BuildEvent + * @access public + * @see BuildEvent::getTask() + */ + function taskStarted(BuildEvent $event) {} + + /** + * Fired when a task has finished. We don't need specific action on this + * event. So the methods are empty. + * + * @param object The BuildEvent + * @access public + * @see BuildEvent::getException() + */ + function taskFinished(BuildEvent $event) {} + + /** + * Print a message to the stdout. + * + * @param object The BuildEvent + * @access public + * @see BuildEvent::getMessage() + */ + function messageLogged(BuildEvent $event) { + if ($event->getPriority() <= $this->msgOutputLevel) { + $msg = ""; + if ($event->getTask() !== null) { + $name = $event->getTask(); + $name = $name->getTaskName(); + $msg = str_pad("[$name] ", self::LEFT_COLUMN_SIZE, " ", STR_PAD_LEFT); + #for ($i=0; $i < ($this->LEFT_COLUMN_SIZE - strlen($msg)); ++$i) { + # print(" "); + #} + #print($msg); + } + $msg .= $event->getMessage(); + $this->printMessage($msg, $event->getPriority()); + } + } + + /** + * Formats a time micro integer to human readable format. + * + * @param integer The time stamp + * @access private + */ + function _formatTime($micros) { + $seconds = $micros; + $minutes = $seconds / 60; + if ($minutes > 1) { + return sprintf("%1.0f minute%s %0.2f second%s", + $minutes, ($minutes === 1 ? " " : "s "), + $seconds - floor($seconds/60) * 60, ($seconds%60 === 1 ? "" : "s")); + } else { + return sprintf("%0.4f second%s", $seconds, ($seconds%60 === 1 ? "" : "s")); + } + } + + /** + * Prints a message to console. + * + * @param string $message The message to print. + * Should not be null. + * @param int $priority The priority of the message. + * (Ignored in this implementation.) + * @return void + */ + protected function printMessage($message, $priority) { + print($message . $this->lSep); + } +} diff --git a/buildscripts/phing/classes/phing/listener/NoBannerLogger.php b/buildscripts/phing/classes/phing/listener/NoBannerLogger.php new file mode 100644 index 00000000..e222e10c --- /dev/null +++ b/buildscripts/phing/classes/phing/listener/NoBannerLogger.php @@ -0,0 +1,61 @@ +. + */ + +include_once 'phing/listener/DefaultLogger.php'; + +/** + * Extends DefaultLogger to strip out empty targets. This logger is most + * commonly used and also enforced by the default phing invokation scripts + * in bin/. + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.4 $ $Date: 2003/12/24 13:02:08 $ + * @package phing.listener + */ +class NoBannerLogger extends DefaultLogger { + + private $targetName = null; + + function targetStarted(BuildEvent $event) { + $target = $event->getTarget(); + $this->targetName = $target->getName(); + } + + function targetFinished(BuildEvent $event) { + $this->targetName = null; + } + + function messageLogged(BuildEvent $event) { + if ($event->getPriority() > $this->msgOutputLevel || + null === $event->getMessage() || + trim($event->getMessage() === "")) { + return; + } + + if ($this->targetName !== null) { + print($this->lSep . "Target: ".$this->targetName . $this->lSep); + $this->targetName = null; + } + + parent::messageLogged($event); + } +} diff --git a/buildscripts/phing/classes/phing/listener/PearLogger.php b/buildscripts/phing/classes/phing/listener/PearLogger.php new file mode 100644 index 00000000..2bea6655 --- /dev/null +++ b/buildscripts/phing/classes/phing/listener/PearLogger.php @@ -0,0 +1,246 @@ +. + */ + +require_once 'phing/BuildListener.php'; +include_once 'phing/BuildEvent.php'; +require_once 'Log.php'; + +/** + * Writes log messages to PEAR Log. + * + * By default it will log to file in current directory w/ name 'phing.log'. You can customize + * this behavior by setting properties: + * - pear.log.type + * - pear.log.name + * - pear.log.ident (note that this class changes ident to project name) + * - pear.log.conf (note that array values are currently unsupported in Phing property files) + * + * + * phing -f build.xml -logger phing.listener.PearLogger -Dpear.log.type=file -Dpear.log.name=/path/to/log.log + * + * + * @author Hans Lellelid + * @version $Revision: 1.3 $ $Date: 2004/03/15 14:45:06 $ + * @see BuildEvent + * @package phing.listener + */ +class PearLogger implements BuildListener { + + /** + * Size of the left column in output. The default char width is 12. + * @var int + */ + const LEFT_COLUMN_SIZE = 12; + + /** + * The message output level that should be used. The default is + * PROJECT_MSG_VERBOSE. + * @var int + */ + protected $msgOutputLevel = PROJECT_MSG_ERR; + + /** + * Time that the build started + * @var int + */ + protected $startTime; + + /** + * Maps Phing PROJECT_MSG_* constants to PEAR_LOG_* constants. + * @var array + */ + protected static $levelMap = array( PROJECT_MSG_DEBUG => PEAR_LOG_DEBUG, + PROJECT_MSG_INFO => PEAR_LOG_INFO, + PROJECT_MSG_VERBOSE => PEAR_LOG_NOTICE, + PROJECT_MSG_WARN => PEAR_LOG_WARNING, + PROJECT_MSG_ERR => PEAR_LOG_ERR + ); + /** + * Whether logging has been configured. + * @var boolean + */ + protected $logConfigured = false; + + /** + * Configure the logger. + */ + protected function configureLogging() { + + $type = Phing::getDefinedProperty('pear.log.type'); + $name = Phing::getDefinedProperty('pear.log.name'); + $ident = Phing::getDefinedProperty('pear.log.ident'); + $conf = Phing::getDefinedProperty('pear.log.conf'); + + if ($type === null) $type = 'file'; + if ($name === null) $name = 'phing.log'; + if ($ident === null) $ident = 'phing'; + if ($conf === null) $conf = array(); + + $this->logger = Log::singleton($type, $name, $ident, $conf, self::$levelMap[$this->msgOutputLevel]); + } + + /** + * Get the configured PEAR logger to use. + * This method just ensures that logging has been configured and returns the configured logger. + * @return Log + */ + protected function logger() { + if (!$this->logConfigured) { + $this->configureLogging(); + } + return $this->logger; + } + + /** + * Set the msgOutputLevel this logger is to respond to. + * + * Only messages with a message level lower than or equal to the given + * level are output to the log. + * + *

                                                Constants for the message levels are in Project.php. The order of + * the levels, from least to most verbose, is: + * + *

                                                  + *
                                                • PROJECT_MSG_ERR
                                                • + *
                                                • PROJECT_MSG_WARN
                                                • + *
                                                • PROJECT_MSG_INFO
                                                • + *
                                                • PROJECT_MSG_VERBOSE
                                                • + *
                                                • PROJECT_MSG_DEBUG
                                                • + *
                                                + * + * The default message level for DefaultLogger is PROJECT_MSG_ERR. + * + * @param integer the logging level for the logger. + * @access public + */ + function setMessageOutputLevel($level) { + $this->msgOutputLevel = (int) $level; + } + + /** + * Sets the start-time when the build started. Used for calculating + * the build-time. + * + * @param object The BuildEvent + * @access public + */ + + function buildStarted(BuildEvent $event) { + $this->startTime = Phing::currentTimeMillis(); + $this->logger()->setIdent($event->getProject()->getName()); + $this->logger()->info("Starting build with buildfile: ". $event->getProject()->getProperty("phing.file")); + } + + /** + * Prints whether the build succeeded or failed, and any errors that + * occured during the build. Also outputs the total build-time. + * + * @param object The BuildEvent + * @access public + * @see BuildEvent::getException() + */ + function buildFinished(BuildEvent $event) { + $error = $event->getException(); + if ($error === null) { + $msg = "Finished successful build."; + } else { + $msg = "Build failed. [reason: " . $error->getMessage() ."]"; + } + $this->logger()->log($msg . " Total time: " . $this->_formatTime(Phing::currentTimeMillis() - $this->startTime)); + } + + /** + * Prints the current target name + * + * @param object The BuildEvent + * @access public + * @see BuildEvent::getTarget() + */ + function targetStarted(BuildEvent $event) {} + + /** + * Fired when a target has finished. We don't need specific action on this + * event. So the methods are empty. + * + * @param object The BuildEvent + * @access public + * @see BuildEvent::getException() + */ + function targetFinished(BuildEvent $event) {} + + /** + * Fired when a task is started. We don't need specific action on this + * event. So the methods are empty. + * + * @param object The BuildEvent + * @access public + * @see BuildEvent::getTask() + */ + function taskStarted(BuildEvent $event) {} + + /** + * Fired when a task has finished. We don't need specific action on this + * event. So the methods are empty. + * + * @param object The BuildEvent + * @access public + * @see BuildEvent::getException() + */ + function taskFinished(BuildEvent $event) {} + + /** + * Print a message to the stdout. + * + * @param object The BuildEvent + * @access public + * @see BuildEvent::getMessage() + */ + function messageLogged(BuildEvent $event) { + if ($event->getPriority() <= $this->msgOutputLevel) { + $msg = ""; + if ($event->getTask() !== null) { + $name = $event->getTask(); + $name = $name->getTaskName(); + $msg = str_pad("[$name] ", self::LEFT_COLUMN_SIZE, " ", STR_PAD_LEFT); + } + $msg .= $event->getMessage(); + $this->logger()->log($msg, self::$levelMap[$event->getPriority()]); + } + } + + /** + * Formats a time micro integer to human readable format. + * + * @param integer The time stamp + * @access private + */ + function _formatTime($micros) { + $seconds = $micros; + $minutes = $seconds / 60; + if ($minutes > 1) { + return sprintf("%1.0f minute%s %0.2f second%s", + $minutes, ($minutes === 1 ? " " : "s "), + $seconds - floor($seconds/60) * 60, ($seconds%60 === 1 ? "" : "s")); + } else { + return sprintf("%0.4f second%s", $seconds, ($seconds%60 === 1 ? "" : "s")); + } + } +} diff --git a/buildscripts/phing/classes/phing/listener/XmlLogger.php b/buildscripts/phing/classes/phing/listener/XmlLogger.php new file mode 100644 index 00000000..07ff031e --- /dev/null +++ b/buildscripts/phing/classes/phing/listener/XmlLogger.php @@ -0,0 +1,265 @@ +. + */ + + require_once 'phing/listener/BuildLogger.php'; + require_once 'phing/listener/DefaultLogger.php'; + require_once 'phing/system/util/Timer.php'; + /** + * Generates a file in the current directory with + * an XML description of what happened during a build. + * The default filename is "log.xml", but this can be overridden + * with the property XmlLogger.file. + * + * @author Michiel Rook + * @version $Id: XmlLogger.php,v 1.3 2005/02/11 10:51:21 mrook Exp $ + * @package phing.listener + */ + class XmlLogger implements BuildLogger + { + /** XML element name for a build. */ + const BUILD_TAG = "build"; + /** XML element name for a target. */ + const TARGET_TAG = "target"; + /** XML element name for a task. */ + const TASK_TAG = "task"; + /** XML element name for a message. */ + const MESSAGE_TAG = "message"; + /** XML attribute name for a name. */ + const NAME_ATTR = "name"; + /** XML attribute name for a time. */ + const TIME_ATTR = "time"; + /** XML attribute name for a message priority. */ + const PRIORITY_ATTR = "priority"; + /** XML attribute name for a file location. */ + const LOCATION_ATTR = "location"; + /** XML attribute name for an error description. */ + const ERROR_ATTR = "error"; + /** XML element name for a stack trace. */ + const STACKTRACE_TAG = "stacktrace"; + + private $doc = NULL; + + private $buildStartTime = 0; + private $targetStartTime = 0; + private $taskStartTime = 0; + + private $buildElement = NULL; + + private $msgOutputLevel = PROJECT_MSG_DEBUG; + + /** + * Constructs a new BuildListener that logs build events to an XML file. + */ + function __construct() + { + $this->doc = new DOMDocument(); + $this->doc->formatOutput = true; + + $this->buildTimer = new Timer(); + $this->targetTimer = new Timer(); + $this->taskTimer = new Timer(); + } + + /** + * Fired when the build starts, this builds the top-level element for the + * document and remembers the time of the start of the build. + * + * @param BuildEvent Ignored. + */ + function buildStarted(BuildEvent $event) + { + $this->buildTimerStart = Phing::currentTimeMillis(); + $this->buildElement = $this->doc->createElement(XmlLogger::BUILD_TAG); + } + + /** + * Fired when the build finishes, this adds the time taken and any + * error stacktrace to the build element and writes the document to disk. + * + * @param BuildEvent An event with any relevant extra information. + * Will not be null. + */ + function buildFinished(BuildEvent $event) + { + $this->buildTimer->stop(); + + $elapsedTime = Phing::currentTimeMillis() - $this->buildTimerStart; + + $this->buildElement->setAttribute(XmlLogger::TIME_ATTR, DefaultLogger::_formatTime($elapsedTime)); + + if ($event->getException() != null) + { + $this->buildElement->setAttribute(XmlLogger::ERROR_ATTR, $event->getException()->toString()); + + $errText = $this->doc->createCDATASection($event->getException()->getTraceAsString()); + $stacktrace = $this->doc->createElement(XmlLogger::STACKTRACE_TAG); + $stacktrace->appendChild($errText); + $this->buildElement->appendChild($stacktrace); + } + + $outFilename = $event->getProject()->getProperty("XmlLogger.file"); + + if ($outFilename == "") + { + $outFilename = "log.xml"; + } + $writer = new FileWriter($outFilename); + + $writer->write("\n"); + $writer->write($this->doc->saveXML($this->buildElement)); + $writer->close(); + } + /** + * Fired when a target starts building, remembers the current time and the name of the target. + * + * @param BuildEvent An event with any relevant extra information. + * Will not be null. + */ + function targetStarted(BuildEvent $event) + { + $target = $event->getTarget(); + + $this->targetTimerStart = Phing::currentTimeMillis(); + + $this->targetElement = $this->doc->createElement(XmlLogger::TARGET_TAG); + $this->targetElement->setAttribute(XmlLogger::NAME_ATTR, $target->getName()); + } + + /** + * Fired when a target finishes building, this adds the time taken + * to the appropriate target element in the log. + * + * @param BuildEvent An event with any relevant extra information. + * Will not be null. + */ + function targetFinished(BuildEvent $event) + { + $target = $event->getTarget(); + + $elapsedTime = Phing::currentTimeMillis() - $this->targetTimerStart; + + $this->targetElement->setAttribute(XmlLogger::TIME_ATTR, DefaultLogger::_formatTime($elapsedTime)); + + $this->buildElement->appendChild($this->targetElement); + } + + /** + * Fired when a task starts building, remembers the current time and the name of the task. + * + * @param BuildEvent An event with any relevant extra information. + * Will not be null. + */ + function taskStarted(BuildEvent $event) + { + $task = $event->getTask(); + + $this->taskTimerStart = Phing::currentTimeMillis(); + + $this->taskElement = $this->doc->createElement(XmlLogger::TASK_TAG); + $this->taskElement->setAttribute(XmlLogger::NAME_ATTR, $task->getTaskName()); + $this->taskElement->setAttribute(XmlLogger::LOCATION_ATTR, $task->getLocation()->toString()); + } + /** + * Fired when a task finishes building, this adds the time taken + * to the appropriate task element in the log. + * + * @param BuildEvent An event with any relevant extra information. + * Will not be null. + */ + function taskFinished(BuildEvent $event) + { + $task = $event->getTask(); + + $elapsedTime = Phing::currentTimeMillis() - $this->taskTimerStart; + $this->taskElement->setAttribute(XmlLogger::TIME_ATTR, DefaultLogger::_formatTime($elapsedTime)); + + $this->targetElement->appendChild($this->taskElement); + } + + /** + * Fired when a message is logged, this adds a message element to the + * most appropriate parent element (task, target or build) and records + * the priority and text of the message. + * + * @param BuildEvent An event with any relevant extra information. + * Will not be null. + */ + function messageLogged(BuildEvent $event) + { + $priority = $event->getPriority(); + + if ($priority > $this->msgOutputLevel) + { + return; + } + + $messageElement = $this->doc->createElement(XmlLogger::MESSAGE_TAG); + + switch ($priority) + { + case PROJECT_MSG_ERR: + $name = "error"; + break; + + case PROJECT_MSG_WARN: + $name = "warn"; + break; + + case PROJECT_MSG_INFO: + $name = "info"; + break; + + default: + $name = "debug"; + break; + } + + $messageElement->setAttribute(XmlLogger::PRIORITY_ATTR, $name); + + $messageText = $this->doc->createCDATASection($event->getMessage()); + + $messageElement->appendChild($messageText); + + if ($event->getTask() != null) + { + $this->taskElement->appendChild($messageElement); + } + else + if ($event->getTarget() != null) + { + $this->targetElement->appendChild($messageElement); + } + else + if ($this->buildElement != null) + { + $this->buildElement->appendChild($messageElement); + } + } + + /** + * Set the logging level when using this as a Logger + */ + function setMessageOutputLevel($level) + { + $this->msgOutputLevel = $level; + } + }; +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/listener/defaults.properties b/buildscripts/phing/classes/phing/listener/defaults.properties new file mode 100644 index 00000000..f60a3fd5 --- /dev/null +++ b/buildscripts/phing/classes/phing/listener/defaults.properties @@ -0,0 +1,43 @@ +#################################################### +# +# ANSI COLOR LOGGER CONFIGURATION +# +# Format for AnsiColorLogger.*= +# Attribute;Foreground;Background +# +# Attribute is one of the following: +# 0 -> Reset All Attributes (return to normal mode) +# 1 -> Bright (Usually turns on BOLD) +# 2 -> Dim +# 3 -> Underline +# 5 -> link +# 7 -> Reverse +# 8 -> Hidden +# +# Foreground is one of the following: +# 30 -> Black +# 31 -> Red +# 32 -> Green +# 33 -> Yellow +# 34 -> Blue +# 35 -> Magenta +# 36 -> Cyan +# 37 -> White +# +# Background is one of the following: +# 40 -> Black +# 41 -> Red +# 42 -> Green +# 43 -> Yellow +# 44 -> Blue +# 45 -> Magenta +# 46 -> Cyan +# 47 -> White +# +#################################################### + +AnsiColorLogger.ERROR_COLOR=2;31 +AnsiColorLogger.WARNING_COLOR=2;35 +AnsiColorLogger.INFO_COLOR=2;36 +AnsiColorLogger.VERBOSE_COLOR=2;32 +AnsiColorLogger.DEBUG_COLOR=2;34 diff --git a/buildscripts/phing/classes/phing/mappers/FileNameMapper.php b/buildscripts/phing/classes/phing/mappers/FileNameMapper.php new file mode 100644 index 00000000..c8f1f8a9 --- /dev/null +++ b/buildscripts/phing/classes/phing/mappers/FileNameMapper.php @@ -0,0 +1,59 @@ +. + */ + +/** + * Interface for filename mapper classes. + * + * @author Andreas Aderhold, andi@binarycloud.com + * @author Hans Lellelid + * @version $Revision: 1.7 $ + * @package phing.mappers + */ +interface FileNameMapper { + + /** + * The mapper implementation. + * + * @param mixed $sourceFileName The data the mapper works on. + * @return array The data after the mapper has been applied; must be in array format (for some reason). + */ + public function main($sourceFileName); + + /** + * Accessor. Sets the to property. The actual implementation + * depends on the child class. + * + * @param string $to To what this mapper should convert the from string + * @return void + */ + public function setTo($to); + + /** + * Accessor. Sets the from property. What this mapper should + * recognize. The actual implementation is dependent upon the + * child class + * + * @param string $from On what this mapper should work + * @return void + */ + public function setFrom($from); + +} diff --git a/buildscripts/phing/classes/phing/mappers/FlattenMapper.php b/buildscripts/phing/classes/phing/mappers/FlattenMapper.php new file mode 100644 index 00000000..fea5c1e4 --- /dev/null +++ b/buildscripts/phing/classes/phing/mappers/FlattenMapper.php @@ -0,0 +1,55 @@ +. + */ + +require_once 'phing/mappers/FileNameMapper.php'; + +/** + * Removes any directory information from the passed path. + * + * @author Andreas Aderhold + * @version $Revision: 1.9 $ + * @package phing.mappers + */ +class FlattenMapper implements FileNameMapper { + + /** + * The mapper implementation. Returns string with source filename + * but without leading directory information + * + * @param string $sourceFileName The data the mapper works on + * @return array The data after the mapper has been applied + */ + function main($sourceFileName) { + $f = new PhingFile($sourceFileName); + return array($f->getName()); + } + + /** + * Ignored here. + */ + function setTo($to) {} + + /** + * Ignored here. + */ + function setFrom($from) {} + +} diff --git a/buildscripts/phing/classes/phing/mappers/GlobMapper.php b/buildscripts/phing/classes/phing/mappers/GlobMapper.php new file mode 100644 index 00000000..3c178620 --- /dev/null +++ b/buildscripts/phing/classes/phing/mappers/GlobMapper.php @@ -0,0 +1,113 @@ +. + */ + +include_once 'phing/mappers/FileNameMapper.php'; + +/** + * description here + * + * @author Andreas Aderhold, andi@binarycloud.com + * @version $Revision: 1.10 $ + * @package phing.mappers + */ +class GlobMapper implements FileNameMapper { + + /** + * Part of "from" pattern before the *. + */ + private $fromPrefix = null; + + /** + * Part of "from" pattern after the *. + */ + private $fromPostfix = null; + + /** + * Length of the prefix ("from" pattern). + */ + private $prefixLength; + + /** + * Length of the postfix ("from" pattern). + */ + private $postfixLength; + + /** + * Part of "to" pattern before the *. + */ + private $toPrefix = null; + + /** + * Part of "to" pattern after the *. + */ + private $toPostfix = null; + + + function main($_sourceFileName) { + if (($this->fromPrefix === null) + || !StringHelper::startsWith($this->fromPrefix, $_sourceFileName) + || !StringHelper::endsWith($this->fromPostfix, $_sourceFileName)) { + return null; + } + $varpart = $this->_extractVariablePart($_sourceFileName); + $substitution = $this->toPrefix.$varpart.$this->toPostfix; + return array($substitution); + } + + + + function setFrom($from) { + $index = strrpos($from, '*'); + + if ($index === false) { + $this->fromPrefix = $from; + $this->fromPostfix = ""; + } else { + $this->fromPrefix = substr($from, 0, $index); + $this->fromPostfix = substr($from, $index+1); + } + $this->prefixLength = strlen($this->fromPrefix); + $this->postfixLength = strlen($this->fromPostfix); + } + + /** + * Sets the "to" pattern. Required. + */ + function setTo($to) { + $index = strrpos($to, '*'); + if ($index === false) { + $this->toPrefix = $to; + $this->toPostfix = ""; + } else { + $this->toPrefix = substr($to, 0, $index); + $this->toPostfix = substr($to, $index+1); + } + } + + private function _extractVariablePart($_name) { + // ergh, i really hate php's string functions .... all but natural + $start = ($this->prefixLength === 0) ? 0 : $this->prefixLength; + $end = ($this->postfixLength === 0) ? strlen($_name) : strlen($_name) - $this->postfixLength; + $len = $end-$start; + return substr($_name, $start, $len); + } + +} diff --git a/buildscripts/phing/classes/phing/mappers/IdentityMapper.php b/buildscripts/phing/classes/phing/mappers/IdentityMapper.php new file mode 100644 index 00000000..daf80c25 --- /dev/null +++ b/buildscripts/phing/classes/phing/mappers/IdentityMapper.php @@ -0,0 +1,54 @@ +. + */ + +require_once 'phing/mappers/FileNameMapper.php'; + +/** + * This mapper does nothing ;) + * + * @author Andreas Aderhold + * @author Hans Lellelid + * @version $Revision: 1.7 $ + * @package phing.mappers + */ +class IdentityMapper implements FileNameMapper { + + /** + * The mapper implementation. Basically does nothing in this case. + * + * @param string $sourceFileName The data the mapper works on. + * @return array The data after the mapper has been applied + */ + function main($sourceFileName) { + return array($sourceFileName); + } + + /** + * Ignored here. + */ + function setTo($to) {} + + /** + * Ignored here. + */ + function setFrom($from) {} + +} diff --git a/buildscripts/phing/classes/phing/mappers/MergeMapper.php b/buildscripts/phing/classes/phing/mappers/MergeMapper.php new file mode 100644 index 00000000..f10f41c0 --- /dev/null +++ b/buildscripts/phing/classes/phing/mappers/MergeMapper.php @@ -0,0 +1,69 @@ +. + */ + +include_once 'phing/mappers/FileNameMapper.php'; + +/** + * For merging files into a single file. In practice just returns whatever value + * was set for "to". + * + * @author Andreas Aderhold + * @version $Revision: 1.8 $ + * @package phing.mappers + */ +class MergeMapper implements FileNameMapper { + + /** the merge */ + private $mergedFile; + + /** + * The mapper implementation. Basically does nothing in this case. + * + * @param mixed The data the mapper works on + * @returns mixed The data after the mapper has been applied + * @access public + * @author Andreas Aderhold, andi@binarycloud.com + */ + function main($sourceFileName) { + if ($this->mergedFile === null) { + throw new BuildException("MergeMapper error, to attribute not set"); + } + return array($this->mergedFile); + } + + /** + * Accessor. Sets the to property + * + * @param string To what this mapper should convert the from string + * @returns boolean True + * @access public + * @author Andreas Aderhold, andi@binarycloud.com + */ + function setTo($to) { + $this->mergedFile = $to; + } + + /** + * Ignored. + */ + function setFrom($from) {} + +} diff --git a/buildscripts/phing/classes/phing/mappers/RegexpMapper.php b/buildscripts/phing/classes/phing/mappers/RegexpMapper.php new file mode 100644 index 00000000..a3d51976 --- /dev/null +++ b/buildscripts/phing/classes/phing/mappers/RegexpMapper.php @@ -0,0 +1,97 @@ +. + */ + +require_once 'phing/mappers/FileNameMapper.php'; +include_once 'phing/util/StringHelper.php'; +include_once 'phing/util/regexp/Regexp.php'; + +/** + * Uses regular expressions to perform filename transformations. + * + * @author Andreas Aderhold + * @author Hans Lellelid + * @version $Revision: 1.9 $ + * @package phing.mappers + */ +class RegexpMapper implements FileNameMapper { + + /** + * @var string + */ + private $to; + + /** + * The Regexp engine. + * @var Regexp + */ + private $reg; + + function __construct() { + // instantiage regexp matcher here + $this->reg = new Regexp(); + } + + /** + * Sets the "from" pattern. Required. + */ + function setFrom($from) { + $this->reg->SetPattern($from); + } + + /** + * Sets the "to" pattern. Required. + */ + function setTo($to) { + + // [HL] I'm changing the way this works for now to just use string + //$this->to = StringHelper::toCharArray($to); + + $this->to = $to; + } + + function main($sourceFileName) { + if ($this->reg === null || $this->to === null || !$this->reg->matches((string) $sourceFileName)) { + return null; + } + return array($this->replaceReferences($sourceFileName)); + } + + /** + * Replace all backreferences in the to pattern with the matched groups. + * groups of the source. + * @param string $source The source filename. + */ + private function replaceReferences($source) { + + // FIXME + // Can't we just use engine->replace() to handle this? the Preg engine + // will automatically convert \1 references to $1 + + // the expression has already been processed (when ->matches() was run in Main()) + // so no need to pass $source again to the engine. + $groups = (array) $this->reg->getGroups(); + + // replace \1 with value of $groups[1] and return the modified "to" string + return preg_replace('/\\\([\d]+)/e', "\$groups[$1]", $this->to); + } + +} + diff --git a/buildscripts/phing/classes/phing/parser/AbstractHandler.php b/buildscripts/phing/classes/phing/parser/AbstractHandler.php new file mode 100644 index 00000000..6f8d7705 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/AbstractHandler.php @@ -0,0 +1,98 @@ +. + */ + +include_once 'phing/parser/ExpatParseException.php'; + +/** + * This is an abstract class all SAX handler classes must extend + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.6 $ + * @package phing.parser + */ +abstract class AbstractHandler { + + public $parentHandler = null; + public $parser = null; + + /** + * Constructs a SAX handler parser. + * + * The constructor must be called by all derived classes. + * + * @param object the parser object + * @param object the parent handler of this handler + */ + protected function __construct($parser, $parentHandler) { + $this->parentHandler = $parentHandler; + $this->parser = $parser; + $this->parser->setHandler($this); + } + + /** + * Gets invoked when a XML open tag occurs + * + * Must be overloaded by the child class. Throws an ExpatParseException + * if there is no handler registered for an element. + * + * @param string the name of the XML element + * @param array the attributes of the XML element + */ + public function startElement($name, $attribs) { + throw new ExpatParseException("Unexpected element $name"); + } + + /** + * Gets invoked when element closes method. + * + */ + protected function finished() {} + + /** + * Gets invoked when a XML element ends. + * + * Can be overloaded by the child class. But should not. It hands + * over control to the parentHandler of this. + * + * @param string the name of the XML element + */ + public function endElement($name) { + $this->finished(); + $this->parser->setHandler($this->parentHandler); + } + + /** + * Invoked by occurance of #PCDATA. + * + * @param string the name of the XML element + * @exception ExpatParserException if there is no CDATA but method + * was called + * @access public + */ + public function characters($data) { + $s = trim($data); + if (strlen($s) > 0) { + throw new ExpatParseException("Unexpected text '$s'", $this->parser->getLocation()); + } + } +} diff --git a/buildscripts/phing/classes/phing/parser/AbstractSAXParser.php b/buildscripts/phing/classes/phing/parser/AbstractSAXParser.php new file mode 100644 index 00000000..60cf0c11 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/AbstractSAXParser.php @@ -0,0 +1,140 @@ +. + */ + +/** + * The abstract SAX parser class. + * + * This class represents a SAX parser. It is a abstract calss that must be + * implemented by the real parser that must extend this class + * + * @author Andreas Aderhold + * @author Hans Lellelid + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.13 $ + * @package phing.parser + */ +abstract class AbstractSAXParser { + + /** The AbstractHandler object. */ + protected $handler; + + /** + * Constructs a SAX parser + */ + function __construct() {} + + /** + * Sets options for PHP interal parser. Must be implemented by the parser + * class if it should be used. + */ + abstract function parserSetOption($opt, $val); + + /** + * Sets the current element handler object for this parser. Usually this + * is an object using extending "AbstractHandler". + * + * @param AbstractHandler $obj The handler object. + */ + function setHandler( $obj) { + $this->handler = $obj; + } + + /** + * Method that gets invoked when the parser runs over a XML start element. + * + * This method is called by PHP's internal parser funcitons and registered + * in the actual parser implementation. + * It gives control to the current active handler object by calling the + * startElement() method. + * + * BECAUSE OF PROBLEMS WITH EXCEPTIONS BUBBLING UP THROUGH xml_parse() THIS + * METHOD WILL CALL Phing::halt(-1) ON EXCEPTION. + * + * @param object the php's internal parser handle + * @param string the open tag name + * @param array the tag's attributes if any + */ + function startElement($parser, $name, $attribs) { + try { + $this->handler->startElement($name, $attribs); + } catch (Exception $e) { + print "[Exception in XML parsing]\n"; + print $e; + Phing::halt(-1); + } + } + + /** + * Method that gets invoked when the parser runs over a XML close element. + * + * This method is called by PHP's internal parser funcitons and registered + * in the actual parser implementation. + * + * It gives control to the current active handler object by calling the + * endElement() method. + * + * BECAUSE OF PROBLEMS WITH EXCEPTIONS BUBBLING UP THROUGH xml_parse() THIS + * METHOD WILL CALL Phing::halt(-1) ON EXCEPTION. + * + * @param object the php's internal parser handle + * @param string the closing tag name + */ + function endElement($parser, $name) { + try { + $this->handler->endElement($name); + } catch (Exception $e) { + print "[Exception in XML parsing]\n"; + print $e; + Phing::halt(-1); + } + } + + /** + * Method that gets invoked when the parser runs over CDATA. + * + * This method is called by PHP's internal parser functions and registered + * in the actual parser implementation. + * + * It gives control to the current active handler object by calling the + * characters() method. That processes the given CDATA. + * + * BECAUSE OF PROBLEMS WITH EXCEPTIONS BUBBLING UP THROUGH xml_parse() THIS + * METHOD WILL CALL Phing::halt(-1) ON EXCEPTION. + * + * @param resource $parser php's internal parser handle. + * @param string $data the CDATA + */ + function characters($parser, $data) { + try { + $this->handler->characters($data); + } catch (Exception $e) { + print "[Exception in XML parsing]\n"; + print $e; + Phing::halt(-1); + } + } + + /** + * Entrypoint for parser. This method needs to be implemented by the + * child classt that utilizes the concrete parser + */ + abstract function parse(); +} diff --git a/buildscripts/phing/classes/phing/parser/DataTypeHandler.php b/buildscripts/phing/classes/phing/parser/DataTypeHandler.php new file mode 100644 index 00000000..37d757c4 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/DataTypeHandler.php @@ -0,0 +1,144 @@ +. + */ + +include_once 'phing/RuntimeConfigurable.php'; + +/** + * Configures a Project (complete with Targets and Tasks) based on + * a XML build file. + *

                                                + * Design/ZE2 migration note: + * If PHP would support nested classes. All the phing/parser/*Filter + * classes would be nested within this class + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.8 $ $Date: 2005/11/02 13:55:33 $ + * @access public + * @package phing.parser + */ + +class DataTypeHandler extends AbstractHandler { + + private $target; + private $element; + private $wrapper; + + /** + * Constructs a new DataTypeHandler and sets up everything. + * + * @param AbstractSAXParser $parser The XML parser (default: ExpatParser) + * @param AbstractHandler $parentHandler The parent handler that invoked this handler. + * @param ProjectConfigurator $configurator The ProjectConfigurator object + * @param Target $target The target object this datatype is contained in (null for top-level datatypes). + */ + function __construct(AbstractSAXParser $parser, AbstractHandler $parentHandler, ProjectConfigurator $configurator, $target = null) { // FIXME b2 typehinting + parent::__construct($parser, $parentHandler); + $this->target = $target; + $this->configurator = $configurator; + } + + /** + * Executes initialization actions required to setup the data structures + * related to the tag. + *

                                                + * This includes: + *

                                                  + *
                                                • creation of the datatype object
                                                • + *
                                                • calling the setters for attributes
                                                • + *
                                                • adding the type to the target object if any
                                                • + *
                                                • adding a reference to the task (if id attribute is given)
                                                • + *
                                                + * + * @param string the tag that comes in + * @param array attributes the tag carries + * @throws ExpatParseException if attributes are incomplete or invalid + * @access public + */ + function init($propType, $attrs) { + // shorthands + $project = $this->configurator->project; + $configurator = $this->configurator; + + try {//try + $this->element = $project->createDataType($propType); + + if ($this->element === null) { + throw new BuildException("Unknown data type $propType"); + } + + if ($this->target !== null) { + $this->wrapper = new RuntimeConfigurable($this->element, $propType); + $this->wrapper->setAttributes($attrs); + $this->target->addDataType($this->wrapper); + } else { + $configurator->configure($this->element, $attrs, $project); + $configurator->configureId($this->element, $attrs); + } + + } catch (BuildException $exc) { + throw new ExpatParseException($exc, $this->parser->getLocation()); + } + } + + /** + * Handles character data. + * + * @param string the CDATA that comes in + * @access public + */ + function characters($data) { + $project = $this->configurator->project; + try {//try + $this->configurator->addText($project, $this->element, $data); + } catch (BuildException $exc) { + throw new ExpatParseException($exc->getMessage(), $this->parser->getLocation()); + } + } + + /** + * Checks for nested tags within the current one. Creates and calls + * handlers respectively. + * + * @param string the tag that comes in + * @param array attributes the tag carries + * @access public + */ + function startElement($name, $attrs) { + $nef = new NestedElementHandler($this->parser, $this, $this->configurator, $this->element, $this->wrapper, $this->target); + $nef->init($name, $attrs); + } + + /** + * Overrides endElement for data types. Tells the type + * handler that processing the element had been finished so + * handlers know they can perform actions that need to be + * based on the data contained within the element. + * + * @param string the name of the XML element + * @return void + */ + function endElement($name) { + $this->element->parsingComplete(); + parent::endElement($name); + } + +} diff --git a/buildscripts/phing/classes/phing/parser/ExpatParseException.php b/buildscripts/phing/classes/phing/parser/ExpatParseException.php new file mode 100644 index 00000000..d5086c30 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/ExpatParseException.php @@ -0,0 +1,31 @@ +. + */ + +require_once 'phing/BuildException.php'; + +/** + * This class throws errors for Expat, the XML processor. + * + * @author Andreas Aderhold, andi@binarycloud.com + * @version $Revision: 1.5 $ $Date: 2003/11/19 05:48:28 $ + * @package phing.parser + */ +class ExpatParseException extends BuildException {} diff --git a/buildscripts/phing/classes/phing/parser/ExpatParser.php b/buildscripts/phing/classes/phing/parser/ExpatParser.php new file mode 100644 index 00000000..82046f8d --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/ExpatParser.php @@ -0,0 +1,140 @@ +. + */ + +require_once 'phing/parser/AbstractSAXParser.php'; +include_once 'phing/parser/ExpatParseException.php'; +include_once 'phing/system/io/IOException.php'; +include_once 'phing/system/io/FileReader.php'; + +/** + * This class is a wrapper for the PHP's internal expat parser. + * + * It takes an XML file represented by a abstract path name, and starts + * parsing the file and calling the different "trap" methods inherited from + * the AbstractParser class. + * + * Those methods then invoke the represenatative methods in the registered + * handler classes. + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.8 $ $Date: 2005/05/26 13:10:52 $ + * @access public + * @package phing.parser + */ + +class ExpatParser extends AbstractSAXParser { + + /** @var resource */ + private $parser; + + /** @var Reader */ + private $reader; + + private $file; + + private $buffer = 4096; + + private $error_string = ""; + + private $line = 0; + + /** @var Location Current cursor pos in XML file. */ + private $location; + + /** + * Constructs a new ExpatParser object. + * + * The constructor accepts a PhingFile object that represents the filename + * for the file to be parsed. It sets up php's internal expat parser + * and options. + * + * @param Reader $reader The Reader Object that is to be read from. + * @param string $filename Filename to read. + * @throws Exception if the given argument is not a PhingFile object + */ + function __construct(Reader $reader, $filename=null) { + + $this->reader = $reader; + if ($filename !== null) { + $this->file = new PhingFile($filename); + } + $this->parser = xml_parser_create(); + $this->buffer = 4096; + $this->location = new Location(); + xml_set_object($this->parser, $this); + xml_set_element_handler($this->parser, array($this,"startElement"),array($this,"endElement")); + xml_set_character_data_handler($this->parser, array($this, "characters")); + } + + /** + * Override PHP's parser default settings, created in the constructor. + * + * @param string the option to set + * @throws mixed the value to set + * @return boolean true if the option could be set, otherwise false + * @access public + */ + function parserSetOption($opt, $val) { + return xml_parser_set_option($this->parser, $opt, $val); + } + + /** + * Returns the location object of the current parsed element. It describes + * the location of the element within the XML file (line, char) + * + * @return object the location of the current parser + * @access public + */ + function getLocation() { + if ($this->file !== null) { + $path = $this->file->getAbsolutePath(); + } else { + $path = $this->reader->getResource(); + } + $this->location = new Location($path, xml_get_current_line_number($this->parser), xml_get_current_column_number($this->parser)); + return $this->location; + } + + /** + * Starts the parsing process. + * + * @param string the option to set + * @return int 1 if the parsing succeeded + * @throws ExpatParseException if something gone wrong during parsing + * @throws IOException if XML file can not be accessed + * @access public + */ + function parse() { + + while ( ($data = $this->reader->read()) !== -1 ) { + if (!xml_parse($this->parser, $data, $this->reader->eof())) { + $error = xml_error_string(xml_get_error_code($this->parser)); + $e = new ExpatParseException($error, $this->getLocation()); + xml_parser_free($this->parser); + throw $e; + } + } + xml_parser_free($this->parser); + + return 1; + } +} diff --git a/buildscripts/phing/classes/phing/parser/Location.php b/buildscripts/phing/classes/phing/parser/Location.php new file mode 100644 index 00000000..fd79866c --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/Location.php @@ -0,0 +1,72 @@ +. + */ + +/** + * Stores the file name and line number of a XML file + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.6 $ $Date: 2003/12/24 13:02:09 $ + * @access public + * @package phing.parser + */ + +class Location { + + private $fileName; + private $lineNumber; + private $columnNumber; + + /** + * Constructs the location consisting of a file name and line number + * + * @param string the filename + * @param integer the line number + * @param integer the column number + * @access public + */ + function Location($fileName = null, $lineNumber = null, $columnNumber = null) { + $this->fileName = $fileName; + $this->lineNumber = $lineNumber; + $this->columnNumber = $columnNumber; + } + + /** + * Returns the file name, line number and a trailing space. + * + * An error message can be appended easily. For unknown locations, + * returns empty string. + * + * @return string the string representation of this Location object + * @access public + */ + function toString() { + $buf = ""; + if ($this->fileName !== null) { + $buf.=$this->fileName; + if ($this->lineNumber !== null) { + $buf.= ":".$this->lineNumber; + } + $buf.=":".$this->columnNumber; + } + return (string) $buf; + } +} diff --git a/buildscripts/phing/classes/phing/parser/NestedElementHandler.php b/buildscripts/phing/classes/phing/parser/NestedElementHandler.php new file mode 100644 index 00000000..8ecd0ed3 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/NestedElementHandler.php @@ -0,0 +1,186 @@ +. + */ + +include_once 'phing/IntrospectionHelper.php'; +include_once 'phing/TaskContainer.php'; + +/** + * The nested element handler class. + * + * This class handles the occurance of runtime registered tags like + * datatypes (fileset, patternset, etc) and it's possible nested tags. It + * introspects the implementation of the class and sets up the data structures. + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.10 $ $Date: 2005/10/04 19:13:44 $ + * @access public + * @package phing.parser + */ + +class NestedElementHandler extends AbstractHandler { + + /** + * Reference to the parent object that represents the parent tag + * of this nested element + * @var object + */ + private $parent; + + /** + * Reference to the child object that represents the child tag + * of this nested element + * @var object + */ + private $child; + + /** + * Reference to the parent wrapper object + * @var object + */ + private $parentWrapper; + + /** + * Reference to the child wrapper object + * @var object + */ + private $childWrapper; + + /** + * Reference to the related target object + * @var object the target instance + */ + private $target; + + /** + * Constructs a new NestedElement handler and sets up everything. + * + * @param object the ExpatParser object + * @param object the parent handler that invoked this handler + * @param object the ProjectConfigurator object + * @param object the parent object this element is contained in + * @param object the parent wrapper object + * @param object the target object this task is contained in + * @access public + */ + function __construct($parser, $parentHandler, $configurator, $parent, $parentWrapper, $target) { + parent::__construct($parser, $parentHandler); + $this->configurator = $configurator; + if ($parent instanceof TaskAdapter) { + $this->parent = $parent->getProxy(); + } else { + $this->parent = $parent; + } + $this->parentWrapper = $parentWrapper; + $this->target = $target; + } + + /** + * Executes initialization actions required to setup the data structures + * related to the tag. + *

                                                + * This includes: + *

                                                  + *
                                                • creation of the nested element
                                                • + *
                                                • calling the setters for attributes
                                                • + *
                                                • adding the element to the container object
                                                • + *
                                                • adding a reference to the element (if id attribute is given)
                                                • + *
                                                + * + * @param string the tag that comes in + * @param array attributes the tag carries + * @throws ExpatParseException if the setup process fails + * @access public + */ + function init($propType, $attrs) { + $configurator = $this->configurator; + $project = $this->configurator->project; + + // introspect the parent class that is custom + $parentClass = get_class($this->parent); + $ih = IntrospectionHelper::getHelper($parentClass); + try { + if ($this->parent instanceof UnknownElement) { + $this->child = new UnknownElement(strtolower($propType)); + $this->parent->addChild($this->child); + } else { + $this->child = $ih->createElement($project, $this->parent, strtolower($propType)); + } + + $configurator->configureId($this->child, $attrs); + + if ($this->parentWrapper !== null) { + $this->childWrapper = new RuntimeConfigurable($this->child, $propType); + $this->childWrapper->setAttributes($attrs); + $this->parentWrapper->addChild($this->childWrapper); + } else { + $configurator->configure($this->child, $attrs, $project); + $ih->storeElement($project, $this->parent, $this->child, strtolower($propType)); + } + } catch (BuildException $exc) { + throw new ExpatParseException("Error initializing nested element <$propType>", $exc, $this->parser->getLocation()); + } + } + + /** + * Handles character data. + * + * @param string the CDATA that comes in + * @throws ExpatParseException if the CDATA could not be set-up properly + * @access public + */ + function characters($data) { + + $configurator = $this->configurator; + $project = $this->configurator->project; + + if ($this->parentWrapper === null) { + try { + $configurator->addText($project, $this->child, $data); + } catch (BuildException $exc) { + throw new ExpatParseException($exc->getMessage(), $this->parser->getLocation()); + } + } else { + $this->childWrapper->addText($data); + } + } + + /** + * Checks for nested tags within the current one. Creates and calls + * handlers respectively. + * + * @param string the tag that comes in + * @param array attributes the tag carries + * @access public + */ + function startElement($name, $attrs) { + //print(get_class($this) . " name = $name, attrs = " . implode(",",$attrs) . "\n"); + if ($this->child instanceof TaskContainer) { + // taskcontainer nested element can contain other tasks - no other + // nested elements possible + $tc = new TaskHandler($this->parser, $this, $this->configurator, $this->child, $this->childWrapper, $this->target); + $tc->init($name, $attrs); + } else { + $neh = new NestedElementHandler($this->parser, $this, $this->configurator, $this->child, $this->childWrapper, $this->target); + $neh->init($name, $attrs); + } + } +} diff --git a/buildscripts/phing/classes/phing/parser/ProjectConfigurator.php b/buildscripts/phing/classes/phing/parser/ProjectConfigurator.php new file mode 100644 index 00000000..6b69e955 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/ProjectConfigurator.php @@ -0,0 +1,246 @@ +. + */ + +include_once 'phing/system/io/BufferedReader.php'; +include_once 'phing/system/io/FileReader.php'; +include_once 'phing/BuildException.php'; +include_once 'phing/system/lang/FileNotFoundException.php'; +include_once 'phing/system/io/PhingFile.php'; + +/** + * The datatype handler class. + * + * This class handles the occurance of registered datatype tags like + * FileSet + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.17 $ $Date: 2006/01/06 14:57:18 $ + * @access public + * @package phing.parser + */ +class ProjectConfigurator { + + public $project; + public $locator; + + public $buildFile; + public $buildFileParent; + + /** + * Static call to ProjectConfigurator. Use this to configure a + * project. Do not use the new operator. + * + * @param object the Project instance this configurator should use + * @param object the buildfile object the parser should use + * @access public + */ + public static function configureProject(Project $project, PhingFile $buildFile) { + $pc = new ProjectConfigurator($project, $buildFile); + $pc->parse(); + } + + /** + * Constructs a new ProjectConfigurator object + * This constructor is private. Use a static call to + * configureProject to configure a project. + * + * @param object the Project instance this configurator should use + * @param object the buildfile object the parser should use + * @access private + */ + function __construct(Project $project, PhingFile $buildFile) { + $this->project = $project; + $this->buildFile = new PhingFile($buildFile->getAbsolutePath()); + $this->buildFileParent = new PhingFile($this->buildFile->getParent()); + } + + /** + * Creates the ExpatParser, sets root handler and kick off parsing + * process. + * + * @throws BuildException if there is any kind of execption during + * the parsing process + * @access private + */ + protected function parse() { + try { + $reader = new BufferedReader(new FileReader($this->buildFile)); + $reader->open(); + $parser = new ExpatParser($reader); + $parser->parserSetOption(XML_OPTION_CASE_FOLDING,0); + $parser->setHandler(new RootHandler($parser, $this)); + $this->project->log("parsing buildfile ".$this->buildFile->getName(), PROJECT_MSG_VERBOSE); + $parser->parse(); + $reader->close(); + } catch (Exception $exc) { + throw new BuildException("Error reading project file", $exc); + } + } + + /** + * Configures an element and resolves eventually given properties. + * + * @param object the element to configure + * @param array the element's attributes + * @param object the project this element belongs to + * @throws Exception if arguments are not valid + * @throws BuildException if attributes can not be configured + * @access public + */ + function configure($target, $attrs, Project $project) { + + if ($target instanceof TaskAdapter) { + $target = $target->getProxy(); + } + + // if the target is an UnknownElement, this means that the tag had not been registered + // when the enclosing element (task, target, etc.) was configured. It is possible, however, + // that the tag was registered (e.g. using ) after the original configuration. + // ... so, try to load it again: + if ($target instanceof UnknownElement) { + $tryTarget = $project->createTask($target->getTaskType()); + if ($tryTarget) { + $target = $tryTarget; + } + } + + $bean = get_class($target); + $ih = IntrospectionHelper::getHelper($bean); + + foreach ($attrs as $key => $value) { + if ($key == 'id') { + continue; + // throw new BuildException("Id must be set Extermnally"); + } + $value = self::replaceProperties($project, $value, $project->getProperties()); + try { // try to set the attribute + $ih->setAttribute($project, $target, strtolower($key), $value); + } catch (BuildException $be) { + // id attribute must be set externally + if ($key !== "id") { + throw $be; + } + } + } + } + + /** + * Configures the #CDATA of an element. + * + * @param object the project this element belongs to + * @param object the element to configure + * @param string the element's #CDATA + * @access public + */ + function addText($project, $target, $text = null) { + if ($text === null || strlen(trim($text)) === 0) { + return; + } + $ih = IntrospectionHelper::getHelper(get_class($target)); + $text = self::replaceProperties($project, $text, $project->getProperties()); + $ih->addText($project, $target, $text); + } + + /** + * Stores a configured child element into its parent object + * + * @param object the project this element belongs to + * @param object the parent element + * @param object the child element + * @param string the XML tagname + * @access public + */ + function storeChild($project, $parent, $child, $tag) { + $ih = IntrospectionHelper::getHelper(get_class($parent)); + $ih->storeElement($project, $parent, $child, $tag); + } + + // The following two properties are a sort of hack + // to enable a static function to serve as the callback + // for preg_replace_callback(). Clearly we cannot use object + // variables, since the replaceProperties() is called statically. + // This is IMO better than using global variables in the callback. + + private static $propReplaceProject; + private static $propReplaceProperties; + + /** + * Replace ${} style constructions in the given value with the + * string value of the corresponding data types. This method is + * static. + * + * @param object the project that should be used for property look-ups + * @param string the string to be scanned for property references + * @param array proeprty keys + * @return string the replaced string or null if the string + * itself was null + */ + public static function replaceProperties(Project $project, $value, $keys) { + + if ($value === null) { + return null; + } + + // These are a "hack" to support static callback for preg_replace_callback() + + // make sure these get initialized every time + self::$propReplaceProperties = $keys; + self::$propReplaceProject = $project; + + // Because we're not doing anything special (like multiple passes), + // regex is the simplest / fastest. PropertyTask, though, uses + // the old parsePropertyString() method, since it has more stringent + // requirements. + + $sb = preg_replace_callback('/\$\{([^}]+)\}/', array('ProjectConfigurator', 'replacePropertyCallback'), $value); + return $sb; + } + + /** + * Private [static] function for use by preg_replace_callback to replace a single param. + * This method makes use of a static variable to hold the + */ + private static function replacePropertyCallback($matches) + { + $propertyName = $matches[1]; + if (!isset(self::$propReplaceProperties[$propertyName])) { + self::$propReplaceProject->log('Property ${'.$propertyName.'} has not been set.', PROJECT_MSG_VERBOSE); + return $matches[0]; + } else { + self::$propReplaceProject->log('Property ${'.$propertyName.'} => ' . self::$propReplaceProperties[$propertyName], PROJECT_MSG_DEBUG); + } + return self::$propReplaceProperties[$propertyName]; + } + + /** + * Scan Attributes for the id attribute and maybe add a reference to + * project. + * + * @param object the element's object + * @param array the element's attributes + */ + function configureId(&$target, $attr) { + if (isset($attr['id']) && $attr['id'] !== null) { + $this->project->addReference($attr['id'], $target); + } + } +} diff --git a/buildscripts/phing/classes/phing/parser/ProjectHandler.php b/buildscripts/phing/classes/phing/parser/ProjectHandler.php new file mode 100644 index 00000000..54486ec9 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/ProjectHandler.php @@ -0,0 +1,146 @@ +. + */ + +require_once 'phing/parser/AbstractHandler.php'; +require_once 'phing/system/io/PhingFile.php'; + +/** + * Handler class for the XML element This class handles all elements + * under the element. + * + * @author Andreas Aderhold + * @copyright (c) 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.14 $ $Date: 2005/10/04 19:13:44 $ + * @access public + * @package phing.parser + */ +class ProjectHandler extends AbstractHandler { + + /** + * The phing project configurator object. + * @var ProjectConfigurator + */ + private $configurator; + + /** + * Constructs a new ProjectHandler + * + * @param object the ExpatParser object + * @param object the parent handler that invoked this handler + * @param object the ProjectConfigurator object + * @access public + */ + function __construct($parser, $parentHandler, $configurator) { + $this->configurator = $configurator; + parent::__construct($parser, $parentHandler); + } + + /** + * Executes initialization actions required to setup the project. Usually + * this method handles the attributes of a tag. + * + * @param string the tag that comes in + * @param array attributes the tag carries + * @param object the ProjectConfigurator object + * @throws ExpatParseException if attributes are incomplete or invalid + * @access public + */ + function init($tag, $attrs) { + $def = null; + $name = null; + $id = null; + $baseDir = null; + + // some shorthands + $project = $this->configurator->project; + $buildFileParent = $this->configurator->buildFileParent; + + foreach ($attrs as $key => $value) { + if ($key === "default") { + $def = $value; + } elseif ($key === "name") { + $name = $value; + } elseif ($key === "id") { + $id = $value; + } elseif ($key === "basedir") { + $baseDir = $value; + } else { + throw new ExpatParseException("Unexpected attribute '$key'"); + } + } + if ($def === null) { + throw new ExpatParseException("The default attribute of project is required"); + } + $project->setDefaultTarget($def); + + if ($name !== null) { + $project->setName($name); + $project->addReference($name, $project); + } + + if ($id !== null) { + $project->addReference($id, $project); + } + + if ($project->getProperty("project.basedir") !== null) { + $project->setBasedir($project->getProperty("project.basedir")); + } else { + if ($baseDir === null) { + $project->setBasedir($buildFileParent->getAbsolutePath()); + } else { + // check whether the user has specified an absolute path + $f = new PhingFile($baseDir); + if ($f->isAbsolute()) { + $project->setBasedir($baseDir); + } else { + $project->setBaseDir($project->resolveFile($baseDir, $buildFileParent)); + } + } + } + } + + /** + * Handles start elements within the tag by creating and + * calling the required handlers for the detected element. + * + * @param string the tag that comes in + * @param array attributes the tag carries + * @throws ExpatParseException if a unxepected element occurs + * @access public + */ + function startElement($name, $attrs) { + + $project = $this->configurator->project; + $types = $project->getDataTypeDefinitions(); + + if ($name == "target") { + $tf = new TargetHandler($this->parser, $this, $this->configurator); + $tf->init($name, $attrs); + } elseif (isset($types[$name])) { + $tyf = new DataTypeHandler($this->parser, $this, $this->configurator); + $tyf->init($name, $attrs); + } else { + $tf = new TaskHandler($this->parser, $this, $this->configurator); + $tf->init($name, $attrs); + } + } +} + diff --git a/buildscripts/phing/classes/phing/parser/RootHandler.php b/buildscripts/phing/classes/phing/parser/RootHandler.php new file mode 100644 index 00000000..28afb5d5 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/RootHandler.php @@ -0,0 +1,82 @@ +. + */ + +require_once 'phing/parser/AbstractHandler.php'; +include_once 'phing/parser/ExpatParseException.php'; +include_once 'phing/parser/ProjectHandler.php'; + +/** + * Root filter class for a phing buildfile. + * + * The root filter is called by the parser first. This is where the phing + * specific parsing starts. RootHandler decides what to do next. + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.7 $ + * @package phing.parser + */ +class RootHandler extends AbstractHandler { + + /** + * The phing project configurator object + */ + private $configurator; + + /** + * Constructs a new RootHandler + * + * The root filter is required so the parser knows what to do. It's + * called by the ExpatParser that is instatiated in ProjectConfigurator. + * + * It recieves the expat parse object ref and a reference to the + * configurator + * + * @param AbstractSAXParser $parser The ExpatParser object. + * @param ProjectConfigurator $configurator The ProjectConfigurator object. + */ + function __construct(AbstractSAXParser $parser, ProjectConfigurator $configurator) { + $this->configurator = $configurator; + parent::__construct($parser, $this); + } + + /** + * Kick off a custom action for a start element tag. + * + * The root element of our buildfile is the <project> element. The + * root filter handles this element if it occurs, creates ProjectHandler + * to handle any nested tags & attributes of the <project> tag, + * and calls init. + * + * @param string $tag The xml tagname + * @param array $attrs The attributes of the tag + * @throws ExpatParseException if the first element within our build file + * is not the >project< element + */ + function startElement($tag, $attrs) { + if ($tag === "project") { + $ph = new ProjectHandler($this->parser, $this, $this->configurator); + $ph->init($tag, $attrs); + } else { + throw new ExpatParseException("Unexpected tag <$tag> in top-level of build file.", $this->parser->getLocation()); + } + } +} diff --git a/buildscripts/phing/classes/phing/parser/TargetHandler.php b/buildscripts/phing/classes/phing/parser/TargetHandler.php new file mode 100644 index 00000000..7ca94b44 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/TargetHandler.php @@ -0,0 +1,149 @@ +. + */ + +require_once 'phing/parser/AbstractHandler.php'; + +/** + * The target handler class. + * + * This class handles the occurance of a tag and it's possible + * nested tags (datatypes and tasks). + * + * @author Andreas Aderhold + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.10 $ + * @package phing.parser + */ +class TargetHandler extends AbstractHandler { + + /** + * Reference to the target object that represents the currently parsed + * target. + * @var object the target instance + */ + private $target; + + /** + * The phing project configurator object + * @var ProjectConfigurator + */ + private $configurator; + + /** + * Constructs a new TargetHandler + * + * @param object the ExpatParser object + * @param object the parent handler that invoked this handler + * @param object the ProjectConfigurator object + */ + function __construct(AbstractSAXParser $parser, AbstractHandler $parentHandler, ProjectConfigurator $configurator) { + parent::__construct($parser, $parentHandler); + $this->configurator = $configurator; + } + + /** + * Executes initialization actions required to setup the data structures + * related to the tag. + *

                                                + * This includes: + *

                                                  + *
                                                • creation of the target object
                                                • + *
                                                • calling the setters for attributes
                                                • + *
                                                • adding the target to the project
                                                • + *
                                                • adding a reference to the target (if id attribute is given)
                                                • + *
                                                + * + * @param string the tag that comes in + * @param array attributes the tag carries + * @throws ExpatParseException if attributes are incomplete or invalid + */ + function init($tag, $attrs) { + $name = null; + $depends = ""; + $ifCond = null; + $unlessCond = null; + $id = null; + $description = null; + + foreach($attrs as $key => $value) { + if ($key==="name") { + $name = (string) $value; + } else if ($key==="depends") { + $depends = (string) $value; + } else if ($key==="if") { + $ifCond = (string) $value; + } else if ($key==="unless") { + $unlessCond = (string) $value; + } else if ($key==="id") { + $id = (string) $value; + } else if ($key==="description") { + $description = (string)$value; + } else { + throw new ExpatParseException("Unexpected attribute '$key'", $this->parser->getLocation()); + } + } + + if ($name === null) { + throw new ExpatParseException("target element appears without a name attribute", $this->parser->getLocation()); + } + + // shorthand + $project = $this->configurator->project; + + $this->target = new Target(); + $this->target->setName($name); + $this->target->setIf($ifCond); + $this->target->setUnless($unlessCond); + $this->target->setDescription($description); + + $project->addTarget($name, $this->target); + + if ($id !== null && $id !== "") { + $project->addReference($id, $this->target); + } + // take care of dependencies + if (strlen($depends) > 0) { + $this->target->setDepends($depends); + } + + } + + /** + * Checks for nested tags within the current one. Creates and calls + * handlers respectively. + * + * @param string the tag that comes in + * @param array attributes the tag carries + */ + function startElement($name, $attrs) { + // shorthands + $project = $this->configurator->project; + $types = $project->getDataTypeDefinitions(); + + if (isset($types[$name])) { + $th = new DataTypeHandler($this->parser, $this, $this->configurator, $this->target); + $th->init($name, $attrs); + } else { + $tmp = new TaskHandler($this->parser, $this, $this->configurator, $this->target, null, $this->target); + $tmp->init($name, $attrs); + } + } +} diff --git a/buildscripts/phing/classes/phing/parser/TaskHandler.php b/buildscripts/phing/classes/phing/parser/TaskHandler.php new file mode 100644 index 00000000..976aebf2 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/TaskHandler.php @@ -0,0 +1,229 @@ +. + */ + +include_once 'phing/UnknownElement.php'; + +/** + * The task handler class. + * + * This class handles the occurance of a tag and it's possible + * nested tags (datatypes and tasks) that may be unknown off bat and are + * initialized on the fly. + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.10 $ + * @package phing.parser + */ +class TaskHandler extends AbstractHandler { + + /** + * Reference to the target object that contains the currently parsed + * task + * @var object the target instance + */ + private $target; + + /** + * Reference to the target object that represents the currently parsed + * target. This must not necessarily be a target, hence extra variable. + * @var object the target instance + */ + private $container; + + /** + * Reference to the task object that represents the currently parsed + * target. + * @var Task + */ + private $task; + + /** + * Wrapper for the parent element, if any. The wrapper for this + * element will be added to this wrapper as a child. + * @var RuntimeConfigurable + */ + private $parentWrapper; + + /** + * Wrapper for this element which takes care of actually configuring + * the element, if this element is contained within a target. + * Otherwise the configuration is performed with the configure method. + * @see ProjectHelper::configure(Object,AttributeList,Project) + */ + private $wrapper; + + /** + * The phing project configurator object + * @var ProjectConfigurator + */ + private $configurator; + + /** + * Constructs a new TaskHandler and sets up everything. + * + * @param AbstractSAXParser The ExpatParser object + * @param object $parentHandler The parent handler that invoked this handler + * @param ProjectConfigurator $configurator + * @param TaskContainer $container The container object this task is contained in (null for top-level tasks). + * @param RuntimeConfigurable $parentWrapper Wrapper for the parent element, if any. + * @param Target $target The target object this task is contained in (null for top-level tasks). + */ + function __construct(AbstractSAXParser $parser, $parentHandler, ProjectConfigurator $configurator, $container = null, $parentWrapper = null, $target = null) { + + parent::__construct($parser, $parentHandler); + + if (($container !== null) && !($container instanceof TaskContainer)) { + throw new Exception("Argument expected to be a TaskContainer, got something else"); + } + if (($parentWrapper !== null) && !($parentWrapper instanceof RuntimeConfigurable)) { + throw new Exception("Argument expected to be a RuntimeConfigurable, got something else."); + } + if (($target !== null) && !($target instanceof Target)) { + throw new Exception("Argument expected to be a Target, got something else"); + } + + $this->configurator = $configurator; + $this->container = $container; + $this->parentWrapper = $parentWrapper; + $this->target = $target; + } + + /** + * Executes initialization actions required to setup the data structures + * related to the tag. + *

                                                + * This includes: + *

                                                  + *
                                                • creation of the task object
                                                • + *
                                                • calling the setters for attributes
                                                • + *
                                                • adding the task to the container object
                                                • + *
                                                • adding a reference to the task (if id attribute is given)
                                                • + *
                                                • executing the task if the container is the <project> + * element
                                                • + *
                                                + * + * @param string $tag The tag that comes in + * @param array $attrs Attributes the tag carries + * @throws ExpatParseException if attributes are incomplete or invalid + */ + function init($tag, $attrs) { + // shorthands + try { + $configurator = $this->configurator; + $project = $this->configurator->project; + + $this->task = $project->createTask($tag); + } catch (BuildException $be) { + // swallow here, will be thrown again in + // UnknownElement->maybeConfigure if the problem persists. + print("Swallowing exception: ".$be->getMessage() . "\n"); + } + + // the task is not known of bat, try to load it on thy fly + if ($this->task === null) { + $this->task = new UnknownElement($tag); + $this->task->setProject($project); + $this->task->setTaskType($tag); + $this->task->setTaskName($tag); + } + + // add file position information to the task (from parser) + // should be used in task exceptions to provide details + $this->task->setLocation($this->parser->getLocation()); + $configurator->configureId($task, $attrs); + + if ($this->container) { + $this->container->addTask($this->task); + } + + // Top level tasks don't have associated targets + // FIXME: if we do like Ant 1.6 and create an implicitTarget in the projectconfigurator object + // then we don't need to check for null here ... but there's a lot of stuff that will break if we + // do that at this point. + if ($this->target !== null) { + $this->task->setOwningTarget($this->target); + $this->task->init(); + $this->wrapper = $this->task->getRuntimeConfigurableWrapper(); + $this->wrapper->setAttributes($attrs); + if ($this->parentWrapper !== null) { // this may not make sense only within this if-block, but it + // seems to address current use cases adequately + $this->parentWrapper->addChild($this->wrapper); + } + } else { + $this->task->init(); + $configurator->configure($this->task, $attrs, $project); + } + } + + /** + * Executes the task at once if it's directly beneath the tag. + */ + protected function finished() { + if ($this->task !== null && $this->target === null) { + try { + $this->task->main(); + } catch (Exception $e) { + $this->task->log($e->getMessage(), PROJECT_MSG_ERR); + throw $e; + } + } + } + + /** + * Handles character data. + * + * @param string $data The CDATA that comes in + */ + function characters($data) { + if ($this->wrapper === null) { + $configurator = $this->configurator; + $project = $this->configurator->project; + try { // try + $configurator->addText($project, $this->task, $data); + } catch (BuildException $exc) { + throw new ExpatParseException($exc->getMessage(), $this->parser->getLocation()); + } + } else { + $this->wrapper->addText($data); + } + } + + /** + * Checks for nested tags within the current one. Creates and calls + * handlers respectively. + * + * @param string $name The tag that comes in + * @param array $attrs Attributes the tag carries + */ + function startElement($name, $attrs) { + $project = $this->configurator->project; + if ($this->task instanceof TaskContainer) { + //print("TaskHandler::startElement() (TaskContainer) name = $name, attrs = " . implode(",",$attrs) . "\n"); + $th = new TaskHandler($this->parser, $this, $this->configurator, $this->task, $this->wrapper, $this->target); + $th->init($name, $attrs); + } else { + //print("TaskHandler::startElement() name = $name, attrs = " . implode(",",$attrs) . "\n"); + $tmp = new NestedElementHandler($this->parser, $this, $this->configurator, $this->task, $this->wrapper, $this->target); + $tmp->init($name, $attrs); + } + } +} diff --git a/buildscripts/phing/classes/phing/system/io/BufferedReader.php b/buildscripts/phing/classes/phing/system/io/BufferedReader.php new file mode 100644 index 00000000..4946985c --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/BufferedReader.php @@ -0,0 +1,170 @@ +. +*/ + +include_once 'phing/system/io/Reader.php'; + +/* + * Convenience class for reading files. + * + * @author Yannick Lecaillez + * @version $Revision: 1.6 $ $Date: 2005/12/27 19:12:13 $ + * @access public + * @see FilterReader + * @package phing.system.io +*/ +class BufferedReader extends Reader { + + private $bufferSize = 0; + private $buffer = null; + private $bufferPos = 0; + + /** + * The Reader we are buffering for. + */ + private $in; + + /** + * + * @param object $reader The reader (e.g. FileReader). + * @param integer $buffsize The size of the buffer we should use for reading files. + * A large buffer ensures that most files (all scripts?) are parsed in 1 buffer. + */ + function __construct(Reader $reader, $buffsize = 65536) { + $this->in = $reader; + $this->bufferSize = $buffsize; + } + + /** + * Reads and returns $_bufferSize chunk of data. + * @return mixed buffer or -1 if EOF. + */ + function read($len = null) { + // ignore $len param, not sure how to hanlde it, since + // this should only read bufferSize amount of data. + if ($len !== null) { + $this->currentPosition = ftell($this->fd); + } + + if ( ($data = $this->in->read($this->bufferSize)) !== -1 ) { + + // not all files end with a newline character, so we also need to check EOF + if (!$this->in->eof()) { + + $notValidPart = strrchr($data, "\n"); + $notValidPartSize = strlen($notValidPart); + + if ( $notValidPartSize > 1 ) { + // Block doesn't finish on a EOL + // Find the last EOL and forgot all following stuff + $dataSize = strlen($data); + $validSize = $dataSize - $notValidPartSize + 1; + + $data = substr($data, 0, $validSize); + + // Rewind to the begining of the forgotten stuff. + $this->in->skip(-$notValidPartSize+1); + } + + } // if !EOF + } + return $data; + } + + function skip($n) { + return $this->in->skip($n); + } + + function reset() { + return $this->in->reset(); + } + + function close() { + return $this->in->close(); + } + + function open() { + return $this->in->open(); + } + + /** + * Read a line from input stream. + */ + function readLine() { + $line = null; + while ( ($ch = $this->readChar()) !== -1 ) { + if ( $ch === "\n" ) { + break; + } + $line .= $ch; + } + + // Warning : Not considering an empty line as an EOF + if ( $line === null && $ch !== -1 ) + return ""; + + return $line; + } + + /** + * Reads a single char from the reader. + * @return string single char or -1 if EOF. + */ + function readChar() { + + if ( $this->buffer === null ) { + // Buffer is empty, fill it ... + $read = $this->in->read($this->bufferSize); + if ($read === -1) { + $ch = -1; + } else { + $this->buffer = $read; + return $this->readChar(); // recurse + } + } else { + // Get next buffered char ... + // handle case where buffer is read-in, but is empty. The next readChar() will return -1 EOF, + // so we just return empty string (char) at this point. (Probably could also return -1 ...?) + $ch = ($this->buffer !== "") ? $this->buffer{$this->bufferPos} : ''; + $this->bufferPos++; + if ( $this->bufferPos >= strlen($this->buffer) ) { + $this->buffer = null; + $this->bufferPos = 0; + } + } + + return $ch; + } + + /** + * Returns whether eof has been reached in stream. + * This is important, because filters may want to know if the end of the file (and not just buffer) + * has been reached. + * @return boolean + */ + function eof() { + return $this->in->eof(); + } + + function getResource() { + return $this->in->getResource(); + } +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/BufferedWriter.php b/buildscripts/phing/classes/phing/system/io/BufferedWriter.php new file mode 100644 index 00000000..c982db28 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/BufferedWriter.php @@ -0,0 +1,72 @@ +. + */ + +include_once 'phing/system/io/Writer.php'; + +/** + * Convenience class for writing files. + * + * @author Hans Lellelid + * @version $Revision: 1.10 $ + * @package phing.system.io + */ +class BufferedWriter extends Writer { + + /** + * The size of the buffer in kb. + */ + private $bufferSize = 0; + + /** + * The Writer we are buffering output to. + */ + private $out; + + function __construct(Writer $writer, $buffsize = 8192) { + $this->out = $writer; + $this->bufferSize = $buffsize; + } + + function write($buf, $off = null, $len = null) { + return $this->out->write($buf, $off, $len); + } + + function newLine() { + $this->write(Phing::getProperty('line.separator')); + } + + function getResource() { + return $this->out->getResource(); + } + + function reset() { + return $this->out->reset(); + } + + function close() { + return $this->out->close(); + } + + function open() { + return $this->out->open(); + } + +} diff --git a/buildscripts/phing/classes/phing/system/io/ConsoleReader.php b/buildscripts/phing/classes/phing/system/io/ConsoleReader.php new file mode 100644 index 00000000..33b37619 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/ConsoleReader.php @@ -0,0 +1,84 @@ +. + */ + +include_once 'phing/system/io/Reader.php'; + +/** + * Convenience class for reading console input. + * + * @author Hans Lellelid + * @author Matthew Hershberger + * @version $Revision: 1.4 $ + * @package phing.system.io + */ +class ConsoleReader extends Reader { + + function readLine() { + + $out = fgets(STDIN); // note: default maxlen is 1kb + $out = rtrim($out); + + return $out; + } + + /** + * + * @param int $len Num chars to read. + * @return string chars read or -1 if eof. + */ + function read($len = null) { + + $out = fread(STDIN, $len); + + + return $out; + // FIXME + // read by chars doesn't work (yet?) with PHP stdin. Maybe + // this is just a language feature, maybe there's a way to get + // ability to read chars w/o ? + + } + + function close() { + // STDIN is always open + } + + function open() { + // STDIN is always open + } + + /** + * Whether eof has been reached with stream. + * @return boolean + */ + function eof() { + return feof(STDIN); + } + + /** + * Returns path to file we are reading. + * @return string + */ + function getResource() { + return "console"; + } +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/FileReader.php b/buildscripts/phing/classes/phing/system/io/FileReader.php new file mode 100644 index 00000000..cbea2c7e --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/FileReader.php @@ -0,0 +1,179 @@ +. + */ + +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/system/io/Reader.php'; + +/** + * Convenience class for reading files. The constructor of this + * @package phing.system.io + */ + +class FileReader extends Reader { + + protected $file; + protected $fd; + + protected $currentPosition = 0; + protected $mark = 0; + + function __construct($file, $exclusive = false) { + + if ($file instanceof PhingFile) { + $this->file = $file; + } elseif (is_string($file)) { + $this->file = new PhingFile($file); + } else { + throw new Exception("Illegal argument type to " . __METHOD__); + } + } + + function skip($n) { + $this->open(); + + $start = $this->currentPosition; + + $ret = @fseek($this->fd, $n, SEEK_CUR); + if ( $ret === -1 ) + return -1; + + $this->currentPosition = ftell($this->fd); + + if ( $start > $this->currentPosition ) + $skipped = $start - $this->currentPosition; + else + $skipped = $this->currentPosition - $start; + + return $skipped; + } + + /** + * Read data from file. + * @param int $len Num chars to read. + * @return string chars read or -1 if eof. + */ + function read($len = null) { + $this->open(); + if (feof($this->fd)) { + return -1; + } + + // Compute length to read + // possible that filesize($this->file) will be larger than + // available bytes to read, but that's fine -- better to err on high end + $length = ($len === null) ? filesize($this->file->getAbsolutePath()) : $len; + + // Read data + $out = fread($this->fd, $length + 1); // adding 1 seems to ensure that next call to read() will return EOF (-1) + $this->currentPosition = ftell($this->fd); + + return $out; + } + + function mark($n = null) { + $this->mark = $this->currentPosition; + } + + function reset() { + // goes back to last mark, by default this would be 0 (i.e. rewind file). + fseek($this->fd, SEEK_SET, $this->mark); + $this->mark = 0; + } + + function close() { + if ($this->fd === null) { + return true; + } + + if (false === @fclose($this->fd)) { + // FAILED. + $msg = "Cannot fclose " . $this->file->__toString() . " $php_errormsg"; + throw new IOException($msg); + } else { + $this->fd = null; + return true; + } + } + + function open() { + global $php_errormsg; + + if ($this->fd === null) { + $this->fd = @fopen($this->file->getAbsolutePath(), "rb"); + } + + if ($this->fd === false) { + // fopen FAILED. + // Add error from php to end of log message. $php_errormsg. + $msg = "Cannot fopen ".$this->file->getAbsolutePath().". $php_errormsg"; + throw new IOException($msg); + } + + if (false) { + // Locks don't seem to work on windows??? HELP!!!!!!!!! + // if (FALSE === @flock($fp, LOCK_EX)) { // FAILED. + $msg = "Cannot acquire flock on $file. $php_errormsg"; + throw new IOException($msg); + } + + return true; + } + + /** + * Whether eof has been reached with stream. + * @return boolean + */ + function eof() { + return feof($this->fd); + } + + /** + * Reads a entire file and stores the data in the variable + * passed by reference. + * + * @param string $file String. Path and/or name of file to read. + * @param object &$rBuffer Reference. Variable of where to put contents. + * + * @return TRUE on success. Err object on failure. + * @author Charlie Killian, charlie@tizac.com + */ + function readInto(&$rBuffer) { + + $this->open(); + + $fileSize = $this->file->length(); + if ($fileSize === false) { + $msg = "Cannot get filesize of " . $this->file->__toString() . " $php_errormsg"; + throw new IOException($msg); + } + $rBuffer = fread($this->fd, $fileSize); + $this->close(); + } + + /** + * Returns path to file we are reading. + * @return string + */ + function getResource() { + return $this->file->toString(); + } +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/FileSystem.php b/buildscripts/phing/classes/phing/system/io/FileSystem.php new file mode 100644 index 00000000..2802ddfb --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/FileSystem.php @@ -0,0 +1,657 @@ +. + */ + +/** + * This is an abstract class for platform specific filesystem implementations + * you have to implement each method in the platform specific filesystem implementation + * classes Your local filesytem implementation must extend this class. + * You should also use this class as a template to write your local implementation + * Some native PHP filesystem specific methods are abstracted here as well. Anyway + * you _must_ always use this methods via a PhingFile object (that by nature uses the + * *FileSystem drivers to access the real filesystem via this class using natives. + * + * FIXME: + * - Error handling reduced to min fallthrough runtime excetions + * more precise errorhandling is done by the PhingFile class + * + * @author Charlie Killian + * @author Hans Lellelid + * @version $Revision: 1.11 $ + * @package phing.system.io + */ +abstract class FileSystem { + + /* properties for simple boolean attributes */ + const BA_EXISTS = 0x01; + const BA_REGULAR = 0x02; + const BA_DIRECTORY = 0x04; + const BA_HIDDEN = 0x08; + + /** Instance for getFileSystem() method. */ + private static $fs; + + /** + * Static method to return the FileSystem singelton representing + * this platform's local filesystem driver. + */ + function getFileSystem() { + if (self::$fs === null) { + switch(Phing::getProperty('host.fstype')) { + case 'UNIX': + include_once 'phing/system/io/UnixFileSystem.php'; + self::$fs = new UnixFileSystem(); + break; + case 'WIN32': + include_once 'phing/system/io/Win32FileSystem.php'; + self::$fs = new Win32FileSystem(); + break; + case 'WINNT': + include_once 'phing/system/io/WinNTFileSystem.php'; + self::$fs = new WinNTFileSystem(); + break; + default: + throw new Exception("Host uses unsupported filesystem, unable to proceed"); + } + } + return self::$fs; + } + + /* -- Normalization and construction -- */ + + /** + * Return the local filesystem's name-separator character. + */ + abstract function getSeparator(); + + /** + * Return the local filesystem's path-separator character. + */ + abstract function getPathSeparator(); + + /** + * Convert the given pathname string to normal form. If the string is + * already in normal form then it is simply returned. + */ + abstract function normalize($strPath); + + /** + * Compute the length of this pathname string's prefix. The pathname + * string must be in normal form. + */ + abstract function prefixLength($pathname); + + /** + * Resolve the child pathname string against the parent. + * Both strings must be in normal form, and the result + * will be a string in normal form. + */ + abstract function resolve($parent, $child); + + /** + * Resolve the given abstract pathname into absolute form. Invoked by the + * getAbsolutePath and getCanonicalPath methods in the PhingFile class. + */ + abstract function resolveFile(PhingFile $f); + + /** + * Return the parent pathname string to be used when the parent-directory + * argument in one of the two-argument PhingFile constructors is the empty + * pathname. + */ + abstract function getDefaultParent(); + + /** + * Post-process the given URI path string if necessary. This is used on + * win32, e.g., to transform "/c:/foo" into "c:/foo". The path string + * still has slash separators; code in the PhingFile class will translate them + * after this method returns. + */ + abstract function fromURIPath($path); + + /* -- Path operations -- */ + + /** + * Tell whether or not the given abstract pathname is absolute. + */ + abstract function isAbsolute(PhingFile $f); + + /** + * canonicalize filename by checking on disk + * @return mixed Canonical path or false if the file doesn't exist. + */ + function canonicalize($strPath) { + return @realpath($strPath); + } + + /* -- Attribute accessors -- */ + + /** + * Return the simple boolean attributes for the file or directory denoted + * by the given abstract pathname, or zero if it does not exist or some + * other I/O error occurs. + */ + function getBooleanAttributes($f) { + throw new Exception("SYSTEM ERROR method getBooleanAttributes() not implemented by fs driver"); + } + + /** + * Check whether the file or directory denoted by the given abstract + * pathname may be accessed by this process. If the second argument is + * false, then a check for read access is made; if the second + * argument is true, then a check for write (not read-write) + * access is made. Return false if access is denied or an I/O error + * occurs. + */ + function checkAccess(PhingFile $f, $write = false) { + // we clear stat cache, its expensive to look up from scratch, + // but we need to be sure + @clearstatcache(); + + + // Shouldn't this be $f->GetAbsolutePath() ? + // And why doesn't GetAbsolutePath() work? + + $strPath = (string) $f->getPath(); + + // FIXME + // if file object does denote a file that yet not existst + // path rights are checked + if (!@file_exists($strPath) && !is_dir($strPath)) { + $strPath = $f->getParent(); + if ($strPath === null || !is_dir($strPath)) { + $strPath = Phing::getProperty("user.dir"); + } + //$strPath = dirname($strPath); + } + + if (!$write) { + return (boolean) @is_readable($strPath); + } else { + return (boolean) @is_writable($strPath); + } + } + + /** + * Return the time at which the file or directory denoted by the given + * abstract pathname was last modified, or zero if it does not exist or + * some other I/O error occurs. + */ + function getLastModifiedTime(PhingFile $f) { + + if (!$f->exists()) { + return 0; + } + + @clearstatcache(); + $strPath = (string) $f->getPath(); + $mtime = @filemtime($strPath); + if (false === $mtime) { + // FAILED. Log and return err. + $msg = "FileSystem::Filemtime() FAILED. Cannot can not get modified time of $strPath. $php_errormsg"; + throw new Exception($msg); + } else { + return (int) $mtime; + } + } + + /** + * Return the length in bytes of the file denoted by the given abstract + * pathname, or zero if it does not exist, is a directory, or some other + * I/O error occurs. + */ + function getLength(PhingFile $f) { + $strPath = (string) $f->getAbsolutePath(); + $fs = filesize((string) $strPath); + if ($fs !== false) { + return $fs; + } else { + $msg = "FileSystem::Read() FAILED. Cannot get filesize of $strPath. $php_errormsg"; + throw new Exception($msg); + } + } + + /* -- File operations -- */ + + /** + * Create a new empty file with the given pathname. Return + * true if the file was created and false if a + * file or directory with the given pathname already exists. Throw an + * IOException if an I/O error occurs. + * + * @param string Path of the file to be created. + * + * @throws IOException + */ + function createNewFile($strPathname) { + if (@file_exists($strPathname)) + return false; + + // Create new file + $fp = @fopen($strPathname, "w"); + if ($fp === false) { + throw new IOException("The file \"$strPathname\" could not be created"); + } + @fclose($fp); + return true; + } + + /** + * Delete the file or directory denoted by the given abstract pathname, + * returning true if and only if the operation succeeds. + */ + function delete(PhingFile $f) { + if ($f->isDirectory()) { + return $this->rmdir($f->getPath()); + } else { + return $this->unlink($f->getPath()); + } + } + + /** + * Arrange for the file or directory denoted by the given abstract + * pathname to be deleted when Phing::shutdown is called, returning + * true if and only if the operation succeeds. + */ + function deleteOnExit($f) { + throw new Exception("deleteOnExit() not implemented by local fs driver"); + } + + /** + * List the elements of the directory denoted by the given abstract + * pathname. Return an array of strings naming the elements of the + * directory if successful; otherwise, return null. + */ + function listDir(PhingFile $f) { + $strPath = (string) $f->getAbsolutePath(); + $d = @dir($strPath); + if (!$d) { + return null; + } + $list = array(); + while($entry = $d->read()) { + if ($entry != "." && $entry != "..") { + array_push($list, $entry); + } + } + $d->close(); + unset($d); + return $list; + } + + /** + * Create a new directory denoted by the given abstract pathname, + * returning true if and only if the operation succeeds. + */ + function createDirectory(&$f) { + return @mkdir($f->getAbsolutePath(),0755); + } + + /** + * Rename the file or directory denoted by the first abstract pathname to + * the second abstract pathname, returning true if and only if + * the operation succeeds. + * + * @param PhingFile $f1 abstract source file + * @param PhingFile $f2 abstract destination file + * @return void + * @throws Exception if rename cannot be performed + */ + function rename(PhingFile $f1, PhingFile $f2) { + // get the canonical paths of the file to rename + $src = $f1->getAbsolutePath(); + $dest = $f2->getAbsolutePath(); + if (false === @rename($src, $dest)) { + $msg = "Rename FAILED. Cannot rename $src to $dest. $php_errormsg"; + throw new Exception($msg); + } + } + + /** + * Set the last-modified time of the file or directory denoted by the + * given abstract pathname returning true if and only if the + * operation succeeds. + * @return void + * @throws Exception + */ + function setLastModifiedTime(PhingFile $f, $time) { + $path = $f->getPath(); + $success = @touch($path, $time); + if (!$success) { + throw new Exception("Could not create directory due to: $php_errormsg"); + } + } + + /** + * Mark the file or directory denoted by the given abstract pathname as + * read-only, returning true if and only if the operation + * succeeds. + */ + function setReadOnly($f) { + throw new Exception("setReadonle() not implemented by local fs driver"); + } + + /* -- Filesystem interface -- */ + + /** + * List the available filesystem roots, return array of PhingFile objects + */ + function listRoots() { + throw new Exception("SYSTEM ERROR [listRoots() not implemented by local fs driver]"); + } + + /* -- Basic infrastructure -- */ + + /** + * Compare two abstract pathnames lexicographically. + */ + function compare($f1, $f2) { + throw new Exception("SYSTEM ERROR [compare() not implemented by local fs driver]"); + } + + /** + * Copy a file. + * + * @param PhingFile $src Source path and name file to copy. + * @param PhingFile $dest Destination path and name of new file. + * + * @return void + * @throws Exception if file cannot be copied. + */ + function copy(PhingFile $src, PhingFile $dest) { + global $php_errormsg; + $srcPath = $src->getAbsolutePath(); + $destPath = $dest->getAbsolutePath(); + + if (false === @copy($srcPath, $destPath)) { // Copy FAILED. Log and return err. + // Add error from php to end of log message. $php_errormsg. + $msg = "FileSystem::copy() FAILED. Cannot copy $srcPath to $destPath. $php_errormsg"; + throw new Exception($msg); + } + + try { + $dest->setMode($src->getMode()); + } catch(Exception $exc) { + // [MA] does chmod returns an error on systems that do not support it ? + // eat it up for now. + } + } + + /** + * Change the permissions on a file or directory. + * + * @param pathname String. Path and name of file or directory. + * @param mode Int. The mode (permissions) of the file or + * directory. If using octal add leading 0. eg. 0777. + * Mode is affected by the umask system setting. + * + * @return void + * @throws Exception if operation failed. + */ + function chmod($pathname, $mode) { + $str_mode = decoct($mode); // Show octal in messages. + if (false === @chmod($pathname, $mode)) {// FAILED. + $msg = "FileSystem::chmod() FAILED. Cannot chmod $pathname. Mode $str_mode. $php_errormsg"; + throw new Exception($msg); + } + } + + /** + * Locks a file and throws an Exception if this is not possible. + * @return void + * @throws Exception + */ + function lock(PhingFile $f) { + $filename = $f->getPath(); + $fp = @fopen($filename, "w"); + $result = @flock($fp, LOCK_EX); + @fclose($fp); + if (!$result) { + throw new Exception("Could not lock file '$filename'"); + } + } + + /** + * Unlocks a file and throws an IO Error if this is not possible. + * + * @throws Exception + * @return void + */ + function unlock(PhingFile $f) { + $filename = $f->getPath(); + $fp = @fopen($filename, "w"); + $result = @flock($fp, LOCK_UN); + fclose($fp); + if (!$result) { + throw new Exception("Could not unlock file '$filename'"); + } + } + + /** + * Delete a file. + * + * @param file String. Path and/or name of file to delete. + * + * @return void + * @throws Exception - if an error is encountered. + */ + function unlink($file) { + global $php_errormsg; + if (false === @unlink($file)) { + $msg = "FileSystem::unlink() FAILED. Cannot unlink '$file'. $php_errormsg"; + throw new Exception($msg); + } + } + + /** + * Symbolically link a file to another name. + * + * Currently symlink is not implemented on Windows. Don't use if the application is to be portable. + * + * @param string $target Path and/or name of file to link. + * @param string $link Path and/or name of link to be created. + * @return void + */ + function symlink($target, $link) { + + // If Windows OS then symlink() will report it is not supported in + // the build. Use this error instead of checking for Windows as the OS. + + if (false === @symlink($target, $link)) { + // Add error from php to end of log message. $php_errormsg. + $msg = "FileSystem::Symlink() FAILED. Cannot symlink '$target' to '$link'. $php_errormsg"; + throw new Exception($msg); + } + + } + + /** + * Set the modification and access time on a file to the present time. + * + * @param string $file Path and/or name of file to touch. + * @param int $time + * @return void + */ + function touch($file, $time = null) { + global $php_errormsg; + + if (null === $time) { + $error = @touch($file); + } else { + $error = @touch($file, $time); + } + + if (false === $error) { // FAILED. + // Add error from php to end of log message. $php_errormsg. + $msg = "FileSystem::touch() FAILED. Cannot touch '$file'. $php_errormsg"; + throw new Exception($msg); + } + } + + /** + * Delete an empty directory OR a directory and all of its contents. + * + * @param dir String. Path and/or name of directory to delete. + * @param children Boolean. False: don't delete directory contents. + * True: delete directory contents. + * + * @return void + */ + function rmdir($dir, $children = false) { + global $php_errormsg; + + // If children=FALSE only delete dir if empty. + if (false === $children) { + + if (false === @rmdir($dir)) { // FAILED. + // Add error from php to end of log message. $php_errormsg. + $msg = "FileSystem::rmdir() FAILED. Cannot rmdir $dir. $php_errormsg"; + throw new Exception($msg); + } + + } else { // delete contents and dir. + + $handle = @opendir($dir); + + if (false === $handle) { // Error. + + $msg = "FileSystem::rmdir() FAILED. Cannot opendir() $dir. $php_errormsg"; + throw new Exception($msg); + + } else { // Read from handle. + + // Don't error on readdir(). + while (false !== ($entry = @readdir($handle))) { + + if ($entry != '.' && $entry != '..') { + + // Only add / if it isn't already the last char. + // This ONLY serves the purpose of making the Logger + // output look nice:) + + if (strpos(strrev($dir), DIRECTORY_SEPARATOR) === 0) {// there is a / + $next_entry = $dir . $entry; + } else { // no / + $next_entry = $dir . DIRECTORY_SEPARATOR . $entry; + } + + // NOTE: As of php 4.1.1 is_dir doesn't return FALSE it + // returns 0. So use == not ===. + + // Don't error on is_dir() + if (false == @is_dir($next_entry)) { // Is file. + + try { + self::unlink($next_entry); // Delete. + } catch (Exception $e) { + $msg = "FileSystem::Rmdir() FAILED. Cannot FileSystem::Unlink() $next_entry. ". $e->getMessage(); + throw new Exception($msg); + } + + } else { // Is directory. + + try { + self::rmdir($next_entry, true); // Delete + } catch (Exception $e) { + $msg = "FileSystem::rmdir() FAILED. Cannot FileSystem::rmdir() $next_entry. ". $e->getMessage(); + throw new Exception($msg); + } + + } // end is_dir else + } // end .. if + } // end while + } // end handle if + + // Don't error on closedir() + @closedir($handle); + + if (false === @rmdir($dir)) { // FAILED. + // Add error from php to end of log message. $php_errormsg. + $msg = "FileSystem::rmdir() FAILED. Cannot rmdir $dir. $php_errormsg"; + throw new Exception($msg); + } + + } + + } + + /** + * Set the umask for file and directory creation. + * + * @param mode Int. Permissions ususally in ocatal. Use leading 0 for + * octal. Number between 0 and 0777. + * + * @return void + * @throws Exception if there is an error performing operation. + */ + function umask($mode) { + global $php_errormsg; + + // CONSIDERME: + // Throw a warning if mode is 0. PHP converts illegal octal numbers to + // 0 so 0 might not be what the user intended. + + $str_mode = decoct($mode); // Show octal in messages. + + if (false === @umask($mode)) { // FAILED. + // Add error from php to end of log message. $php_errormsg. + $msg = "FileSystem::Umask() FAILED. Value $mode. $php_errormsg"; + throw new Exception($msg); + } + } + + /** + * Compare the modified time of two files. + * + * @param file1 String. Path and name of file1. + * @param file2 String. Path and name of file2. + * + * @return Int. 1 if file1 is newer. + * -1 if file2 is newer. + * 0 if files have the same time. + * Err object on failure. + * + * @throws Exception - if cannot get modified time of either file. + */ + function compareMTimes($file1, $file2) { + + $mtime1 = filemtime($file1); + $mtime2 = filemtime($file2); + + if ($mtime1 === false) { // FAILED. Log and return err. + // Add error from php to end of log message. $php_errormsg. + $msg = "FileSystem::compareMTimes() FAILED. Cannot can not get modified time of $file1."; + throw new Exception($msg); + } elseif ($mtime2 === false) { // FAILED. Log and return err. + // Add error from php to end of log message. $php_errormsg. + $msg = "FileSystem::compareMTimes() FAILED. Cannot can not get modified time of $file2."; + throw new Exception($msg); + } else { // Worked. Log and return compare. + // Compare mtimes. + if ($mtime1 == $mtime2) { + return 0; + } else { + return ($mtime1 < $mtime2) ? -1 : 1; + } // end compare + } + } + +} diff --git a/buildscripts/phing/classes/phing/system/io/FileWriter.php b/buildscripts/phing/classes/phing/system/io/FileWriter.php new file mode 100644 index 00000000..d6265777 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/FileWriter.php @@ -0,0 +1,139 @@ +. + */ + +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/system/io/Writer.php'; + +/** + * Convenience class for reading files. The constructor of this + * + * @package phing.system.io + */ +class FileWriter extends Writer { + + protected $file; + protected $fd; + + /** Whether to append contents to file. */ + protected $append; + + /** Whether we should attempt to lock the file (currently disabled). */ + protected $exclusive; + + /** + * Construct a new FileWriter. + * @param mixed $file PhingFile or string pathname. + * @param boolean $append Append to existing file? + * @param boolean $exclusive Lock file? (currently disabled due to windows incompatibility) + */ + function __construct($file, $append = false, $exclusive = false) { + if ($file instanceof PhingFile) { + $this->file = $file; + } elseif (is_string($file)) { + $this->file = new PhingFile($file); + } else { + throw new Exception("Invalid argument type for \$file."); + } + $this->append = $append; + $this->exclusive = $exclusive; + } + + function close() { + if ($this->fd === null) { + return true; + } + + if (false === @fclose($this->fd)) { + // FAILED. + $msg = "Cannot fclose " . $this->file->__toString() . " $php_errormsg"; + throw new IOException($msg); + } else { + $this->fd = null; + return true; + } + } + + function open() { + if ($this->fd === null) { + if ($this->append) { $flags = "ab"; } else { $flags = "wb"; } + $this->fd = @fopen($this->file->getPath(), $flags); + } + + if ($this->fd === false) { + // fopen FAILED. + // Add error from php to end of log message. $php_errormsg. + $msg = "Cannot fopen ".$this->file->getPath()." $php_errormsg"; + throw new IOException($msg); + } + + if (false) { + // Locks don't seem to work on windows??? HELP!!!!!!!!! + // if (FALSE === @flock($fp, LOCK_EX)) { // FAILED. + $msg = "Cannot acquire flock on $file. $php_errormsg"; + throw new IOException($msg); + } + + return true; + } + + function reset() { + // FIXME -- what exactly should this do, if anything? + // reset to beginning of file (i.e. re-open)? + } + + function writeBuffer($buffer) { + + if (!$this->file->canWrite()) { + throw new IOException("No permission to write to file: " . $this->file->__toString()); + } + + $this->open(); + $result = @fwrite($this->fd, $buffer); + $this->close(); + + if ($result === false) { + throw new IOException("Error writing file: ". $this->file->toString()); + } else { + return true; + } + } + + function write($buf, $off = null, $len = null) { + if ( $off === null && $len === null ) + $to_write = $buf; + else + $to_write = substr($buf, $off, $len); + + $this->open(); + $result = @fwrite($this->fd, $to_write); + + if ( $result === false ) { + throw new IOException("Error writing file."); + } else { + return true; + } + } + + function getResource() { + return $this->file->toString(); + } +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/FilterReader.php b/buildscripts/phing/classes/phing/system/io/FilterReader.php new file mode 100644 index 00000000..8c683408 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/FilterReader.php @@ -0,0 +1,72 @@ +. + */ + +include_once 'phing/system/io/Reader.php'; + +/** + * Convenience class for reading files. The constructor of this + * @package phing.system.io + * + * TODO: All filters should be ProjectComponents, too! + */ +class FilterReader extends Reader { + + protected $in; + + function __construct(Reader $in = null) { + $this->in = $in; + //parent::__construct(new FileReader($file, $exclusive)); + } + + public function setReader(Reader $in) { + $this->in = $in; + } + + public function skip($n) { + return $this->in->skip($n); + } + + /** + * Read data from source. + * FIXME: Clean up this function signature, as it a) params aren't being used + * and b) it doesn't make much sense. + */ + public function read($len = null) { + return $this->in->read($len); + } + + public function reset() { + return $this->in->reset(); + } + + public function close() { + return $this->in->close(); + } + + public function open() { + return $this->in->open(); + } + + function getResource() { + return $this->in->getResource(); + } +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/IOException.php b/buildscripts/phing/classes/phing/system/io/IOException.php new file mode 100644 index 00000000..e2c73b27 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/IOException.php @@ -0,0 +1,28 @@ +. + */ + +/** + * Extends Exception to take advantage of methods therein. + * + * @package phing.system.io + */ +class IOException extends Exception {} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/system/io/PhingFile.php b/buildscripts/phing/classes/phing/system/io/PhingFile.php new file mode 100644 index 00000000..cd881963 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/PhingFile.php @@ -0,0 +1,866 @@ +. + */ + +include_once 'phing/system/io/FileSystem.php'; +include_once 'phing/system/lang/NullPointerException.php'; + +/** + * An abstract representation of file and directory pathnames. + * + * @version $Revision: 1.1 $ + * @package phing.system.io + */ +class PhingFile { + + /** separator string, static, obtained from FileSystem */ + public static $separator; + + /** path separator string, static, obtained from FileSystem (; or :)*/ + public static $pathSeparator; + + /** + * This abstract pathname's normalized pathname string. A normalized + * pathname string uses the default name-separator character and does not + * contain any duplicate or redundant separators. + */ + private $path = null; + + /** The length of this abstract pathname's prefix, or zero if it has no prefix. */ + private $prefixLength = 0; + + /** constructor */ + function __construct($arg1 = null, $arg2 = null) { + + if (self::$separator === null || self::$pathSeparator === null) { + $fs = FileSystem::getFileSystem(); + self::$separator = $fs->getSeparator(); + self::$pathSeparator = $fs->getPathSeparator(); + } + + /* simulate signature identified constructors */ + if ($arg1 instanceof PhingFile && is_string($arg2)) { + $this->_constructFileParentStringChild($arg1, $arg2); + } elseif (is_string($arg1) && ($arg2 === null)) { + $this->_constructPathname($arg1); + } elseif(is_string($arg1) && is_string($arg2)) { + $this->_constructStringParentStringChild($arg1, $arg2); + } else { + if ($arg1 === null) { + throw new NullPointerException("Argument1 to function must not be null"); + } + $this->path = (string) $arg1; + $this->prefixLength = (int) $arg2; + } + } + + /** Returns the length of this abstract pathname's prefix. */ + function getPrefixLength() { + return (int) $this->prefixLength; + } + + /* -- constructors not called by signature match, so we need some helpers --*/ + + function _constructPathname($pathname) { + // obtain ref to the filesystem layer + $fs = FileSystem::getFileSystem(); + + if ($pathname === null) { + throw new NullPointerException("Argument to function must not be null"); + } + + $this->path = (string) $fs->normalize($pathname); + $this->prefixLength = (int) $fs->prefixLength($this->path); + } + + function _constructStringParentStringChild($parent, $child = null) { + // obtain ref to the filesystem layer + $fs = FileSystem::getFileSystem(); + + if ($child === null) { + throw new NullPointerException("Argument to function must not be null"); + } + if ($parent !== null) { + if ($parent === "") { + $this->path = $fs->resolve($fs->getDefaultParent(), $fs->normalize($child)); + } else { + $this->path = $fs->resolve($fs->normalize($parent), $fs->normalize($child)); + } + } else { + $this->path = (string) $fs->normalize($child); + } + $this->prefixLength = (int) $fs->prefixLength($this->path); + } + + function _constructFileParentStringChild($parent, $child = null) { + // obtain ref to the filesystem layer + $fs = FileSystem::getFileSystem(); + + if ($child === null) { + throw new NullPointerException("Argument to function must not be null"); + } + + if ($parent !== null) { + if ($parent->path === "") { + $this->path = $fs->resolve($fs->getDefaultParent(), $fs->normalize($child)); + } else { + $this->path = $fs->resolve($parent->path, $fs->normalize($child)); + } + } else { + $this->path = $fs->normalize($child); + } + $this->prefixLength = $fs->prefixLength($this->path); + } + + /* -- Path-component accessors -- */ + + /** + * Returns the name of the file or directory denoted by this abstract + * pathname. This is just the last name in the pathname's name + * sequence. If the pathname's name sequence is empty, then the empty + * string is returned. + * + * @return The name of the file or directory denoted by this abstract + * pathname, or the empty string if this pathname's name sequence + * is empty + */ + function getName() { + // that's a lastIndexOf + $index = ((($res = strrpos($this->path, self::$separator)) === false) ? -1 : $res); + if ($index < $this->prefixLength) { + return substr($this->path, $this->prefixLength); + } + return substr($this->path, $index + 1); + } + + /** + * Returns the pathname string of this abstract pathname's parent, or + * null if this pathname does not name a parent directory. + * + * The parent of an abstract pathname consists of the pathname's prefix, + * if any, and each name in the pathname's name sequence except for the last. + * If the name sequence is empty then the pathname does not name a parent + * directory. + * + * @return The pathname string of the parent directory named by this + * abstract pathname, or null if this pathname does not name a parent + */ + function getParent() { + // that's a lastIndexOf + $index = ((($res = strrpos($this->path, self::$separator)) === false) ? -1 : $res); + if ($index < $this->prefixLength) { + if (($this->prefixLength > 0) && (strlen($this->path > $this->prefixLength))) { + return substr($this->path, 0, $this->prefixLength); + } + return null; + } + return substr($this->path, 0, $index); + } + + /** + * Returns the abstract pathname of this abstract pathname's parent, + * or null if this pathname does not name a parent directory. + * + * The parent of an abstract pathname consists of the pathname's prefix, + * if any, and each name in the pathname's name sequence except for the + * last. If the name sequence is empty then the pathname does not name + * a parent directory. + * + * @return The abstract pathname of the parent directory named by this + * abstract pathname, or null if this pathname + * does not name a parent + */ + function getParentFile() { + $p = $this->getParent(); + if ($p === null) { + return null; + } + return new PhingFile((string) $p, (int) $this->prefixLength); + } + + /** + * Converts this abstract pathname into a pathname string. The resulting + * string uses the default name-separator character to separate the names + * in the name sequence. + * + * @return The string form of this abstract pathname + */ + function getPath() { + return (string) $this->path; + } + + /** + * Tests whether this abstract pathname is absolute. The definition of + * absolute pathname is system dependent. On UNIX systems, a pathname is + * absolute if its prefix is "/". On Win32 systems, a pathname is absolute + * if its prefix is a drive specifier followed by "\\", or if its prefix + * is "\\". + * + * @return true if this abstract pathname is absolute, false otherwise + */ + function isAbsolute() { + return ($this->prefixLength !== 0); + } + + + /** + * Returns the absolute pathname string of this abstract pathname. + * + * If this abstract pathname is already absolute, then the pathname + * string is simply returned as if by the getPath method. + * If this abstract pathname is the empty abstract pathname then + * the pathname string of the current user directory, which is named by the + * system property user.dir, is returned. Otherwise this + * pathname is resolved in a system-dependent way. On UNIX systems, a + * relative pathname is made absolute by resolving it against the current + * user directory. On Win32 systems, a relative pathname is made absolute + * by resolving it against the current directory of the drive named by the + * pathname, if any; if not, it is resolved against the current user + * directory. + * + * @return The absolute pathname string denoting the same file or + * directory as this abstract pathname + * @see #isAbsolute() + */ + function getAbsolutePath() { + $fs = FileSystem::getFileSystem(); + return $fs->resolveFile($this); + } + + /** + * Returns the absolute form of this abstract pathname. Equivalent to + * getAbsolutePath. + * + * @return The absolute abstract pathname denoting the same file or + * directory as this abstract pathname + */ + function getAbsoluteFile() { + return new PhingFile((string) $this->getAbsolutePath()); + } + + + /** + * Returns the canonical pathname string of this abstract pathname. + * + * A canonical pathname is both absolute and unique. The precise + * definition of canonical form is system-dependent. This method first + * converts this pathname to absolute form if necessary, as if by invoking the + * getAbsolutePath() method, and then maps it to its unique form in a + * system-dependent way. This typically involves removing redundant names + * such as "." and .. from the pathname, resolving symbolic links + * (on UNIX platforms), and converting drive letters to a standard case + * (on Win32 platforms). + * + * Every pathname that denotes an existing file or directory has a + * unique canonical form. Every pathname that denotes a nonexistent file + * or directory also has a unique canonical form. The canonical form of + * the pathname of a nonexistent file or directory may be different from + * the canonical form of the same pathname after the file or directory is + * created. Similarly, the canonical form of the pathname of an existing + * file or directory may be different from the canonical form of the same + * pathname after the file or directory is deleted. + * + * @return The canonical pathname string denoting the same file or + * directory as this abstract pathname + */ + function getCanonicalPath() { + $fs = FileSystem::getFileSystem(); + return $fs->canonicalize($this->path); + } + + + /** + * Returns the canonical form of this abstract pathname. Equivalent to + * getCanonicalPath(. + * + * @return PhingFile The canonical pathname string denoting the same file or + * directory as this abstract pathname + */ + function getCanonicalFile() { + return new PhingFile($this->getCanonicalPath()); + } + + /** + * Converts this abstract pathname into a file: URL. The + * exact form of the URL is system-dependent. If it can be determined that + * the file denoted by this abstract pathname is a directory, then the + * resulting URL will end with a slash. + * + * Usage note: This method does not automatically escape + * characters that are illegal in URLs. It is recommended that new code + * convert an abstract pathname into a URL by first converting it into a + * URI, via the toURI() method, and then converting the URI + * into a URL via the URI::toURL() + * + * @return A URL object representing the equivalent file URL + * + * + */ + function toURL() { + /* + // URL class not implemented yet + return new URL("file", "", $this->_slashify($this->getAbsolutePath(), $this->isDirectory())); + */ + } + + /** + * Constructs a file: URI that represents this abstract pathname. + * Not implemented yet + */ + function toURI() { + /* + $f = $this->getAbsoluteFile(); + $sp = (string) $this->slashify($f->getPath(), $f->isDirectory()); + if (StringHelper::startsWith('//', $sp)) + $sp = '//' + sp; + return new URI('file', null, $sp, null); + */ + } + + function _slashify($path, $isDirectory) { + $p = (string) $path; + + if (self::$separator !== '/') { + $p = str_replace(self::$separator, '/', $p); + } + + if (!StringHelper::startsWith('/', $p)) { + $p = '/'.$p; + } + + if (!StringHelper::endsWith('/', $p) && $isDirectory) { + $p = $p.'/'; + } + + return $p; + } + + /* -- Attribute accessors -- */ + + /** + * Tests whether the application can read the file denoted by this + * abstract pathname. + * + * @return true if and only if the file specified by this + * abstract pathname exists and can be read by the + * application; false otherwise + */ + function canRead() { + $fs = FileSystem::getFileSystem(); + + if ($fs->checkAccess($this)) { + return (boolean) @is_readable($this->getAbsolutePath()); + } + return false; + } + + /** + * Tests whether the application can modify to the file denoted by this + * abstract pathname. + * + * @return true if and only if the file system actually + * contains a file denoted by this abstract pathname and + * the application is allowed to write to the file; + * false otherwise. + * + */ + function canWrite() { + $fs = FileSystem::getFileSystem(); + return $fs->checkAccess($this, true); + } + + /** + * Tests whether the file denoted by this abstract pathname exists. + * + * @return true if and only if the file denoted by this + * abstract pathname exists; false otherwise + * + */ + function exists() { + if ($this->isFile()) { + return @file_exists($this->path); + } else { + return @is_dir($this->path); + } + } + + /** + * Tests whether the file denoted by this abstract pathname is a + * directory. + * + * @return true if and only if the file denoted by this + * abstract pathname exists and is a directory; + * false otherwise + * + */ + function isDirectory() { + $fs = FileSystem::getFileSystem(); + if ($fs->checkAccess($this) !== true) { + throw new IOException("No read access to ".$this->path); + } + return @is_dir($this->path); + } + + /** + * Tests whether the file denoted by this abstract pathname is a normal + * file. A file is normal if it is not a directory and, in + * addition, satisfies other system-dependent criteria. Any non-directory + * file created by a Java application is guaranteed to be a normal file. + * + * @return true if and only if the file denoted by this + * abstract pathname exists and is a normal file; + * false otherwise + */ + function isFile() { + //$fs = FileSystem::getFileSystem(); + return @is_file($this->path); + } + + /** + * Tests whether the file named by this abstract pathname is a hidden + * file. The exact definition of hidden is system-dependent. On + * UNIX systems, a file is considered to be hidden if its name begins with + * a period character ('.'). On Win32 systems, a file is considered to be + * hidden if it has been marked as such in the filesystem. Currently there + * seems to be no way to dermine isHidden on Win file systems via PHP + * + * @return true if and only if the file denoted by this + * abstract pathname is hidden according to the conventions of the + * underlying platform + */ + function isHidden() { + $fs = FileSystem::getFileSystem(); + if ($fs->checkAccess($this) !== true) { + throw new IOException("No read access to ".$this->path); + } + return (($fs->getBooleanAttributes($this) & $fs->BA_HIDDEN) !== 0); + } + + /** + * Returns the time that the file denoted by this abstract pathname was + * last modified. + * + * @return A integer value representing the time the file was + * last modified, measured in milliseconds since the epoch + * (00:00:00 GMT, January 1, 1970), or 0 if the + * file does not exist or if an I/O error occurs + */ + function lastModified() { + $fs = FileSystem::getFileSystem(); + if ($fs->checkAccess($this) !== true) { + throw new IOException("No read access to " . $this->path); + } + return $fs->getLastModifiedTime($this); + } + + /** + * Returns the length of the file denoted by this abstract pathname. + * The return value is unspecified if this pathname denotes a directory. + * + * @return The length, in bytes, of the file denoted by this abstract + * pathname, or 0 if the file does not exist + */ + function length() { + $fs = FileSystem::getFileSystem(); + if ($fs->checkAccess($this) !== true) { + throw new IOException("No read access to ".$this->path."\n"); + } + return $fs->getLength($this); + } + + /** + * Convenience method for returning the contents of this file as a string. + * This method uses file_get_contents() to read file in an optimized way. + * @return string + * @throws Exception - if file cannot be read + */ + function contents() { + if (!$this->canRead() || !$this->isFile()) { + throw new IOException("Cannot read file contents!"); + } + return file_get_contents($this->getAbsolutePath()); + } + + /* -- File operations -- */ + + /** + * Atomically creates a new, empty file named by this abstract pathname if + * and only if a file with this name does not yet exist. The check for the + * existence of the file and the creation of the file if it does not exist + * are a single operation that is atomic with respect to all other + * filesystem activities that might affect the file. + * + * @return true if the named file does not exist and was + * successfully created; false if the named file + * already exists + * @throws IOException if file can't be created + */ + function createNewFile($parents=true, $mode=0777) { + $file = FileSystem::getFileSystem()->createNewFile($this->path); + return $file; + } + + /** + * Deletes the file or directory denoted by this abstract pathname. If + * this pathname denotes a directory, then the directory must be empty in + * order to be deleted. + * + * @return true if and only if the file or directory is + * successfully deleted; false otherwise + */ + function delete() { + $fs = FileSystem::getFileSystem(); + if ($fs->checkAccess($this, true) !== true) { + throw new IOException("No read access to " . $this->path."\n"); + } + return $fs->delete($this); + } + + /** + * Requests that the file or directory denoted by this abstract pathname + * be deleted when php terminates. Deletion will be attempted only for + * normal termination of php and if and if only Phing::shutdown() is + * called. + * + * Once deletion has been requested, it is not possible to cancel the + * request. This method should therefore be used with care. + * + */ + function deleteOnExit() { + $fs = FileSystem::getFileSystem(); + $fs->deleteOnExit($this); + } + + /** + * Returns an array of strings naming the files and directories in the + * directory denoted by this abstract pathname. + * + * If this abstract pathname does not denote a directory, then this + * method returns null Otherwise an array of strings is + * returned, one for each file or directory in the directory. Names + * denoting the directory itself and the directory's parent directory are + * not included in the result. Each string is a file name rather than a + * complete path. + * + * There is no guarantee that the name strings in the resulting array + * will appear in any specific order; they are not, in particular, + * guaranteed to appear in alphabetical order. + * + * @return An array of strings naming the files and directories in the + * directory denoted by this abstract pathname. The array will be + * empty if the directory is empty. Returns null if + * this abstract pathname does not denote a directory, or if an + * I/O error occurs. + * + */ + function listDir($filter = null) { + $fs = FileSystem::getFileSystem(); + return $fs->lister($this, $filter); + } + + function listFiles($filter = null) { + $ss = $this->listDir($filter); + if ($ss === null) { + return null; + } + $n = count($ss); + $fs = array(); + for ($i = 0; $i < $n; $i++) { + $fs[$i] = new PhingFile((string)$this->path, (string)$ss[$i]); + } + return $fs; + } + + /** + * Creates the directory named by this abstract pathname, including any + * necessary but nonexistent parent directories. Note that if this + * operation fails it may have succeeded in creating some of the necessary + * parent directories. + * + * @return true if and only if the directory was created, + * along with all necessary parent directories; false + * otherwise + * @throws IOException + */ + function mkdirs() { + if ($this->exists()) { + return false; + } + try { + if ($this->mkdir()) { + return true; + } + } catch (IOException $ioe) { + // IOException from mkdir() means that directory propbably didn't exist. + } + $parentFile = $this->getParentFile(); + return (($parentFile !== null) && ($parentFile->mkdirs() && $this->mkdir())); + } + + /** + * Creates the directory named by this abstract pathname. + * + * @return true if and only if the directory was created; false otherwise + * @throws IOException + */ + function mkdir() { + $fs = FileSystem::getFileSystem(); + + if ($fs->checkAccess(new PhingFile($this->path), true) !== true) { + throw new IOException("No write access to " . $this->getPath()); + } + return $fs->createDirectory($this); + } + + /** + * Renames the file denoted by this abstract pathname. + * + * @param destFile The new abstract pathname for the named file + * @return true if and only if the renaming succeeded; false otherwise + */ + function renameTo(PhingFile $destFile) { + $fs = FileSystem::getFileSystem(); + if ($fs->checkAccess($this) !== true) { + throw new IOException("No write access to ".$this->getPath()); + } + return $fs->rename($this, $destFile); + } + + /** + * Simple-copies file denoted by this abstract pathname into another + * PhingFile + * + * @param PhingFile $destFile The new abstract pathname for the named file + * @return true if and only if the renaming succeeded; false otherwise + */ + function copyTo(PhingFile $destFile) { + $fs = FileSystem::getFileSystem(); + + if ($fs->checkAccess($this) !== true) { + throw new IOException("No read access to ".$this->getPath()."\n"); + } + + if ($fs->checkAccess($destFile, true) !== true) { + throw new IOException("File::copyTo() No write access to ".$destFile->getPath()); + } + return $fs->copy($this, $destFile); + } + + /** + * Sets the last-modified time of the file or directory named by this + * abstract pathname. + * + * All platforms support file-modification times to the nearest second, + * but some provide more precision. The argument will be truncated to fit + * the supported precision. If the operation succeeds and no intervening + * operations on the file take place, then the next invocation of the + * lastModified method will return the (possibly truncated) time argument + * that was passed to this method. + * + * @param time The new last-modified time, measured in milliseconds since + * the epoch (00:00:00 GMT, January 1, 1970) + * @return true if and only if the operation succeeded; false otherwise + */ + function setLastModified($time) { + $time = (int) $time; + if ($time < 0) { + throw new Exception("IllegalArgumentException, Negative $time\n"); + } + + // FIXME check if accessible + $fs = FileSystem::getFileSystem(); + if ($fs->checkAccess($this, true) !== true) { + throw new IOException("File::setLastModified(). No write access to file\n"); + } + return $fs->setLastModifiedTime($this, $time); + } + + /** + * Marks the file or directory named by this abstract pathname so that + * only read operations are allowed. After invoking this method the file + * or directory is guaranteed not to change until it is either deleted or + * marked to allow write access. Whether or not a read-only file or + * directory may be deleted depends upon the underlying system. + * + * @return true if and only if the operation succeeded; false otherwise + */ + function setReadOnly() { + $fs = FileSystem::getFileSystem(); + if ($fs->checkAccess($this, true) !== true) { + // Error, no write access + throw new IOException("No write access to " . $this->getPath()); + } + return $fs->setReadOnly($this); + } + + /** + * Sets the mode of the file + * @param int $mode Ocatal mode. + */ + function setMode($mode) { + $fs = FileSystem::getFileSystem(); + return $fs->chmod($this->getPath(), $mode); + } + + /** + * Retrieve the mode of this file. + * @return int + */ + function getMode() { + return @fileperms($this->getPath()); + } + + /* -- Filesystem interface -- */ + + /** + * List the available filesystem roots. + * + * A particular platform may support zero or more hierarchically-organized + * file systems. Each file system has a root directory from which all + * other files in that file system can be reached. + * Windows platforms, for example, have a root directory for each active + * drive; UNIX platforms have a single root directory, namely "/". + * The set of available filesystem roots is affected by various system-level + * operations such the insertion or ejection of removable media and the + * disconnecting or unmounting of physical or virtual disk drives. + * + * This method returns an array of PhingFile objects that + * denote the root directories of the available filesystem roots. It is + * guaranteed that the canonical pathname of any file physically present on + * the local machine will begin with one of the roots returned by this + * method. + * + * The canonical pathname of a file that resides on some other machine + * and is accessed via a remote-filesystem protocol such as SMB or NFS may + * or may not begin with one of the roots returned by this method. If the + * pathname of a remote file is syntactically indistinguishable from the + * pathname of a local file then it will begin with one of the roots + * returned by this method. Thus, for example, PhingFile objects + * denoting the root directories of the mapped network drives of a Windows + * platform will be returned by this method, while PhingFile + * objects containing UNC pathnames will not be returned by this method. + * + * @return An array of PhingFile objects denoting the available + * filesystem roots, or null if the set of roots + * could not be determined. The array will be empty if there are + * no filesystem roots. + */ + function listRoots() { + $fs = FileSystem::getFileSystem(); + return (array) $fs->listRoots(); + } + + /* -- Tempfile management -- */ + + /** + * Returns the path to the temp directory. + */ + function getTempDir() { + return Phing::getProperty('php.tmpdir'); + } + + /** + * Static method that creates a unique filename whose name begins with + * $prefix and ends with $suffix in the directory $directory. $directory + * is a reference to a PhingFile Object. + * Then, the file is locked for exclusive reading/writing. + * + * @author manuel holtgrewe, grin@gmx.net + * @throws IOException + * @access public + */ + function createTempFile($prefix, $suffix, PhingFile $directory) { + + // quick but efficient hack to create a unique filename ;-) + $result = null; + do { + $result = new PhingFile($directory, $prefix . substr(md5(time()), 0, 8) . $suffix); + } while (file_exists($result->getPath())); + + $fs = FileSystem::getFileSystem(); + $fs->createNewFile($result->getPath()); + $fs->lock($result); + + return $result; + } + + /** + * If necessary, $File the lock on $File is removed and then the file is + * deleted + * + * @access public + */ + function removeTempFile() { + $fs = FileSystem::getFileSystem(); + // catch IO Exception + $fs->unlock($this); + $this->delete(); + } + + + /* -- Basic infrastructure -- */ + + /** + * Compares two abstract pathnames lexicographically. The ordering + * defined by this method depends upon the underlying system. On UNIX + * systems, alphabetic case is significant in comparing pathnames; on Win32 + * systems it is not. + * + * @param PhingFile $file Th file whose pathname sould be compared to the pathname of this file. + * + * @return int Zero if the argument is equal to this abstract pathname, a + * value less than zero if this abstract pathname is + * lexicographically less than the argument, or a value greater + * than zero if this abstract pathname is lexicographically + * greater than the argument + */ + function compareTo(PhingFile $file) { + $fs = FileSystem::getFileSystem(); + return $fs->compare($this, $file); + } + + /** + * Tests this abstract pathname for equality with the given object. + * Returns true if and only if the argument is not + * null and is an abstract pathname that denotes the same file + * or directory as this abstract pathname. Whether or not two abstract + * pathnames are equal depends upon the underlying system. On UNIX + * systems, alphabetic case is significant in comparing pathnames; on Win32 + * systems it is not. + * @return boolean + */ + function equals($obj) { + if (($obj !== null) && ($obj instanceof PhingFile)) { + return ($this->compareTo($obj) === 0); + } + return false; + } + + /** Backwards compatibility -- use PHP5's native __tostring method. */ + function toString() { + return $this->getPath(); + } + + /** PHP5's native method. */ + function __toString() { + return $this->getPath(); + } +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/Reader.php b/buildscripts/phing/classes/phing/system/io/Reader.php new file mode 100644 index 00000000..1e377378 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/Reader.php @@ -0,0 +1,88 @@ +. +*/ + +/** + * Abstract class for reading character streams. + * @author Hans Lellelid + * @author Yannick Lecaillez + * @version $Revision: 1.5 $ + * @package phing.system.io + */ +abstract class Reader { + + /** + * Read data from source. + * If length is specified, then only that number of chars is read, + * otherwise stream is read until EOF. + * @param int $len + */ + abstract public function read($len = null); + + /** + * Close stream. + */ + abstract public function close(); + + /** + * Open stream for reading. + */ + abstract public function open(); + + /** + * Returns the filename, url, etc. that is being read from. + * This is critical for, e.g., ExpatParser's ability to know + * the filename that is throwing an ExpatParserException, etc. + * @return string + */ + abstract function getResource(); + + /** + * Move stream position relative to current pos. + * @param int $n + */ + public function skip($n) {} + + /** + * Reset the current position in stream to beginning or last mark (if supported). + */ + public function reset() {} + + /** + * If supported, places a "marker" (like a bookmark) at current stream position. + * A subsequent call to reset() will move stream position back + * to last marker (if supported). + */ + public function mark() {} + + /** + * Whether marking is supported. + * @return boolean + */ + public function markSupported() {} + + /** + * Is stream ready for reading. + * @return boolean + */ + public function ready() {} + +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/StringReader.php b/buildscripts/phing/classes/phing/system/io/StringReader.php new file mode 100644 index 00000000..689a2115 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/StringReader.php @@ -0,0 +1,73 @@ +. + */ + +/** + * Dummy class for reading character streams. + * @package phing.system.io + */ +class StringReader extends Reader { + + private $_string; + private $mark = 0; + private $currPos = 0; + + function __construct($string) { + $this->_string = $string; + } + + function skip($n) {} + + function read($len = null) { + if ($len === null) { + return $this->_string; + } else { + if ($this->currPos >= strlen($this->_string)) { + return -1; + } + $out = substr($this->_string, $this->currPos, $len); + $this->currPos += $len; + return $out; + } + } + + function mark() { + $this->mark = $this->currPos; + } + + function reset() { + $this->currPos = $this->mark; + } + + function close() {} + + function open() {} + + function ready() {} + + function markSupported() { + return true; + } + + function getResource() { + return '(string) "'.$this->_string . '"'; + } +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/TokenReader.php b/buildscripts/phing/classes/phing/system/io/TokenReader.php new file mode 100644 index 00000000..a57d994c --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/TokenReader.php @@ -0,0 +1,51 @@ +. +*/ + +include_once 'phing/system/io/Reader.php'; +include_once 'phing/filters/ReplaceTokens.php'; // for class Token + +/** + * Abstract class for reading Tokens from a resource + * + * @author Manuel Holtgewe + * @version $Revision: 1.3 $ + * @access public + * @package phing.system.io + */ +class TokenReader extends Reader { + + /** + * Constructor + */ + function __construct() { + } + + /** + * Reads a token from the resource and returns it as a + * Token object. + * + * @access public + */ + function readToken() { + } +} + +?> diff --git a/buildscripts/phing/classes/phing/system/io/UnixFileSystem.php b/buildscripts/phing/classes/phing/system/io/UnixFileSystem.php new file mode 100644 index 00000000..fb4e49b4 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/UnixFileSystem.php @@ -0,0 +1,266 @@ +. + */ + +include_once 'phing/system/io/FileSystem.php'; + +/** + * UnixFileSystem class. This class encapsulates the basic file system functions + * for platforms using the unix (posix)-stylish filesystem. It wraps php native + * functions suppressing normal PHP error reporting and instead uses Exception + * to report and error. + * + * This class is part of a oop based filesystem abstraction and targeted to run + * on all supported php platforms. + * + * Note: For debugging turn track_errors on in the php.ini. The error messages + * and log messages from this class will then be clearer because $php_errormsg + * is passed as part of the message. + * + * FIXME: + * - Comments + * - Error handling reduced to min, error are handled by PhingFile mainly + * + * @author Andreas Aderhold, andi@binarycloud.com + * @version $Revision: 1.10 $ + * @package phing.system.io + */ +class UnixFileSystem extends FileSystem { + + /** + * returns OS dependant path separator char + */ + function getSeparator() { + return '/'; + } + + /** + * returns OS dependant directory separator char + */ + function getPathSeparator() { + return ':'; + } + + /** + * A normal Unix pathname contains no duplicate slashes and does not end + * with a slash. It may be the empty string. + * + * Check that the given pathname is normal. If not, invoke the real + * normalizer on the part of the pathname that requires normalization. + * This way we iterate through the whole pathname string only once. + */ + function normalize($strPathname) { + + if (empty($strPathname)) { + return; + } + + // Resolve home directories. We assume /home is where all home + // directories reside, b/c there is no other way to do this with + // PHP AFAIK. + if ($strPathname{0} === "~") { + if ($strPathname{1} === "/") { // like ~/foo => /home/user/foo + $strPathname = "/home/" . get_current_user() . substr($strPathname, 1); + } else { // like ~foo => /home/foo + $pos = strpos($strPathname, "/"); + $name = substr($strPathname, 1, $pos - 2); + $strPathname = "/home/" . $name . substr($strPathname, $pos); + } + } + + $n = strlen($strPathname); + $prevChar = 0; + for ($i=0; $i < $n; $i++) { + $c = $strPathname{$i}; + if (($prevChar === '/') && ($c === '/')) { + return self::normalizer($strPathname, $n, $i - 1); + } + $prevChar = $c; + } + if ($prevChar === '/') { + return self::normalizer($strPathname, $n, $n - 1); + } + return $strPathname; + } + + /** + * Normalize the given pathname, whose length is $len, starting at the given + * $offset; everything before this offset is already normal. + */ + protected function normalizer($pathname, $len, $offset) { + if ($len === 0) { + return $pathname; + } + $n = (int) $len; + while (($n > 0) && ($pathname{$n-1} === '/')) { + $n--; + } + if ($n === 0) { + return '/'; + } + $sb = ""; + + if ($offset > 0) { + $sb .= substr($pathname, 0, $offset); + } + $prevChar = 0; + for ($i = $offset; $i < $n; $i++) { + $c = $pathname{$i}; + if (($prevChar === '/') && ($c === '/')) { + continue; + } + $sb .= $c; + $prevChar = $c; + } + return $sb; + } + + /** + * Compute the length of the pathname string's prefix. The pathname + * string must be in normal form. + */ + function prefixLength($pathname) { + if (strlen($pathname === 0)) { + return 0; + } + return (($pathname{0} === '/') ? 1 : 0); + } + + /** + * Resolve the child pathname string against the parent. + * Both strings must be in normal form, and the result + * will be in normal form. + */ + function resolve($parent, $child) { + + if ($child === "") { + return $parent; + } + + if ($child{0} === '/') { + if ($parent === '/') { + return $child; + } + return $parent.$child; + } + + if ($parent === '/') { + return $parent.$child; + } + + return $parent.'/'.$child; + } + + function getDefaultParent() { + return '/'; + } + + function isAbsolute(PhingFile $f) { + return ($f->getPrefixLength() !== 0); + } + + /** + * the file resolver + */ + function resolveFile(PhingFile $f) { + // resolve if parent is a file oject only + if ($this->isAbsolute($f)) { + return $f->getPath(); + } else { + return $this->resolve(Phing::getProperty("user.dir"), $f->getPath()); + } + } + + /* -- most of the following is mapped to the php natives wrapped by FileSystem */ + + /* -- Attribute accessors -- */ + function getBooleanAttributes(&$f) { + //$rv = getBooleanAttributes0($f); + $name = $f->getName(); + $hidden = (strlen($name) > 0) && ($name{0} == '.'); + return ($hidden ? $this->BA_HIDDEN : 0); + } + + /** + * set file readonly on unix + */ + function setReadOnly($f) { + if ($f instanceof File) { + $strPath = (string) $f->getPath(); + $perms = (int) (@fileperms($strPath) & 0444); + return FileSystem::Chmod($strPath, $perms); + } else { + throw new Exception("IllegalArgutmentType: Argument is not File"); + } + } + + /** + * compares file paths lexicographically + */ + function compare($f1, $f2) { + if ( ($f1 instanceof PhingFile) && ($f2 instanceof PhingFile) ) { + $f1Path = $f1->getPath(); + $f2Path = $f2->getPath(); + return (boolean) strcmp((string) $f1Path, (string) $f2Path); + } else { + throw new Exception("IllegalArgutmentType: Argument is not PhingFile"); + } + } + + /* -- fs interface --*/ + + function listRoots() { + if (!$this->checkAccess('/', false)) { + die ("Can not access root"); + } + return array(new PhingFile("/")); + } + + /** + * returns the contents of a directory in an array + */ + function lister($f) { + $dir = @opendir($f->getAbsolutePath()); + if (!$dir) { + throw new Exception("Can't open directory " . $f->__toString()); + } + $vv = array(); + while (($file = @readdir($dir)) !== false) { + if ($file == "." || $file == "..") { + continue; + } + $vv[] = (string) $file; + } + @closedir($dir); + return $vv; + } + + function fromURIPath($p) { + if (StringHelper::endsWith("/", $p) && (strlen($p) > 1)) { + + // "/foo/" --> "/foo", but "/" --> "/" + $p = substr($p, 0, strlen($p) - 1); + + } + + return $p; + } + +} diff --git a/buildscripts/phing/classes/phing/system/io/Win32FileSystem.php b/buildscripts/phing/classes/phing/system/io/Win32FileSystem.php new file mode 100644 index 00000000..c32c21ff --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/Win32FileSystem.php @@ -0,0 +1,477 @@ +. + */ + +include_once 'phing/system/io/FileSystem.php'; + +/** + * @package phing.system.io + */ +class Win32FileSystem extends FileSystem { + + protected $slash; + protected $altSlash; + protected $semicolon; + + private static $driveDirCache = array(); + + function __construct() { + $this->slash = self::getSeparator(); + $this->semicolon = self::getPathSeparator(); + $this->altSlash = ($this->slash === '\\') ? '/' : '\\'; + } + + function isSlash($c) { + return ($c == '\\') || ($c == '/'); + } + + function isLetter($c) { + return ((ord($c) >= ord('a')) && (ord($c) <= ord('z'))) + || ((ord($c) >= ord('A')) && (ord($c) <= ord('Z'))); + } + + function slashify($p) { + if ((strlen($p) > 0) && ($p{0} != $this->slash)) { + return $this->slash.$p; + } + else { + return $p; + } + } + + /* -- Normalization and construction -- */ + + function getSeparator() { + // the ascii value of is the \ + return chr(92); + } + + function getPathSeparator() { + return ';'; + } + + /** + * A normal Win32 pathname contains no duplicate slashes, except possibly + * for a UNC prefix, and does not end with a slash. It may be the empty + * string. Normalized Win32 pathnames have the convenient property that + * the length of the prefix almost uniquely identifies the type of the path + * and whether it is absolute or relative: + * + * 0 relative to both drive and directory + * 1 drive-relative (begins with '\\') + * 2 absolute UNC (if first char is '\\'), else directory-relative (has form "z:foo") + * 3 absolute local pathname (begins with "z:\\") + */ + function normalizePrefix($strPath, $len, $sb) { + $src = 0; + while (($src < $len) && $this->isSlash($strPath{$src})) { + $src++; + } + $c = ""; + if (($len - $src >= 2) + && $this->isLetter($c = $strPath{$src}) + && $strPath{$src + 1} === ':') { + /* Remove leading slashes if followed by drive specifier. + * This hack is necessary to support file URLs containing drive + * specifiers (e.g., "file://c:/path"). As a side effect, + * "/c:/path" can be used as an alternative to "c:/path". */ + $sb .= $c; + $sb .= ':'; + $src += 2; + } + else { + $src = 0; + if (($len >= 2) + && $this->isSlash($strPath{0}) + && $this->isSlash($strPath{1})) { + /* UNC pathname: Retain first slash; leave src pointed at + * second slash so that further slashes will be collapsed + * into the second slash. The result will be a pathname + * beginning with "\\\\" followed (most likely) by a host + * name. */ + $src = 1; + $sb.=$this->slash; + } + } + return $src; + } + + /** Normalize the given pathname, whose length is len, starting at the given + offset; everything before this offset is already normal. */ + protected function normalizer($strPath, $len, $offset) { + if ($len == 0) { + return $strPath; + } + if ($offset < 3) { + $offset = 0; //Avoid fencepost cases with UNC pathnames + } + $src = 0; + $slash = $this->slash; + $sb = ""; + + if ($offset == 0) { + // Complete normalization, including prefix + $src = $this->normalizePrefix($strPath, $len, $sb); + } else { + // Partial normalization + $src = $offset; + $sb .= substr($strPath, 0, $offset); + } + + // Remove redundant slashes from the remainder of the path, forcing all + // slashes into the preferred slash + while ($src < $len) { + $c = $strPath{$src++}; + if ($this->isSlash($c)) { + while (($src < $len) && $this->isSlash($strPath{$src})) { + $src++; + } + if ($src === $len) { + /* Check for trailing separator */ + $sn = (int) strlen($sb); + if (($sn == 2) && ($sb{1} === ':')) { + // "z:\\" + $sb .= $slash; + break; + } + if ($sn === 0) { + // "\\" + $sb .= $slash; + break; + } + if (($sn === 1) && ($this->isSlash($sb{0}))) { + /* "\\\\" is not collapsed to "\\" because "\\\\" marks + the beginning of a UNC pathname. Even though it is + not, by itself, a valid UNC pathname, we leave it as + is in order to be consistent with the win32 APIs, + which treat this case as an invalid UNC pathname + rather than as an alias for the root directory of + the current drive. */ + $sb .= $slash; + break; + } + // Path does not denote a root directory, so do not append + // trailing slash + break; + } else { + $sb .= $slash; + } + } else { + $sb.=$c; + } + } + $rv = (string) $sb; + return $rv; + } + + /** + * Check that the given pathname is normal. If not, invoke the real + * normalizer on the part of the pathname that requires normalization. + * This way we iterate through the whole pathname string only once. + * @param string $strPath + * @return string + */ + function normalize($strPath) { + $n = strlen($strPath); + $slash = $this->slash; + $altSlash = $this->altSlash; + $prev = 0; + for ($i = 0; $i < $n; $i++) { + $c = $strPath{$i}; + if ($c === $altSlash) { + return $this->normalizer($strPath, $n, ($prev === $slash) ? $i - 1 : $i); + } + if (($c === $slash) && ($prev === $slash) && ($i > 1)) { + return $this->normalizer($strPath, $n, $i - 1); + } + if (($c === ':') && ($i > 1)) { + return $this->normalizer($strPath, $n, 0); + } + $prev = $c; + } + if ($prev === $slash) { + return $this->normalizer($strPath, $n, $n - 1); + } + return $strPath; + } + + function prefixLength($strPath) { + $path = (string) $strPath; + $slash = (string) $this->slash; + $n = (int) strlen($path); + if ($n === 0) { + return 0; + } + $c0 = $path{0}; + $c1 = ($n > 1) ? $path{1} : + 0; + if ($c0 === $slash) { + if ($c1 === $slash) { + return 2; // absolute UNC pathname "\\\\foo" + } + return 1; // drive-relative "\\foo" + } + + if ($this->isLetter($c0) && ($c1 === ':')) { + if (($n > 2) && ($path{2}) === $slash) { + return 3; // Absolute local pathname "z:\\foo" */ + } + return 2; // Directory-relative "z:foo" + } + return 0; // Completely relative + } + + function resolve($parent, $child) { + $parent = (string) $parent; + $child = (string) $child; + $slash = (string) $this->slash; + + $pn = (int) strlen($parent); + if ($pn === 0) { + return $child; + } + $cn = (int) strlen($child); + if ($cn === 0) { + return $parent; + } + + $c = $child; + if (($cn > 1) && ($c{0} === $slash)) { + if ($c{1} === $slash) { + // drop prefix when child is a UNC pathname + $c = substr($c, 2); + } + else { + //Drop prefix when child is drive-relative */ + $c = substr($c, 1); + } + } + + $p = $parent; + if ($p{$pn - 1} === $slash) { + $p = substr($p, 0, $pn - 1); + } + return $p.$this->slashify($c); + } + + function getDefaultParent() { + return (string) ("".$this->slash); + } + + function fromURIPath($strPath) { + $p = (string) $strPath; + if ((strlen($p) > 2) && ($p{2} === ':')) { + + // "/c:/foo" --> "c:/foo" + $p = substr($p,1); + + // "c:/foo/" --> "c:/foo", but "c:/" --> "c:/" + if ((strlen($p) > 3) && StringHelper::endsWith('/', $p)) { + $p = substr($p, 0, strlen($p) - 1); + } + } elseif ((strlen($p) > 1) && StringHelper::endsWith('/', $p)) { + // "/foo/" --> "/foo" + $p = substr($p, 0, strlen($p) - 1); + } + return (string) $p; + } + + + /* -- Path operations -- */ + + function isAbsolute(PhingFile $f) { + $pl = (int) $f->getPrefixLength(); + $p = (string) $f->getPath(); + return ((($pl === 2) && ($p{0} === $this->slash)) || ($pl === 3) || ($pl === 1 && $p{0} === $this->slash)); + } + + /** private */ + function _driveIndex($d) { + $d = (string) $d{0}; + if ((ord($d) >= ord('a')) && (ord($d) <= ord('z'))) { + return ord($d) - ord('a'); + } + if ((ord($d) >= ord('A')) && (ord($d) <= ord('Z'))) { + return ord($d) - ord('A'); + } + return -1; + } + + /** private */ + function _getDriveDirectory($drive) { + $drive = (string) $drive{0}; + $i = (int) $this->_driveIndex($drive); + if ($i < 0) { + return null; + } + + $s = (isset(self::$driveDirCache[$i]) ? self::$driveDirCache[$i] : null); + + if ($s !== null) { + return $s; + } + + $s = $this->_getDriveDirectory($i + 1); + self::$driveDirCache[$i] = $s; + return $s; + } + + function _getUserPath() { + //For both compatibility and security, we must look this up every time + return (string) $this->normalize(Phing::getProperty("user.dir")); + } + + function _getDrive($path) { + $path = (string) $path; + $pl = $this->prefixLength($path); + return ($pl === 3) ? substr($path, 0, 2) : null; + } + + function resolveFile(PhingFile $f) { + $path = $f->getPath(); + $pl = (int) $f->getPrefixLength(); + + if (($pl === 2) && ($path{0} === $this->slash)) { + return path; // UNC + } + + if ($pl === 3) { + return $path; // Absolute local + } + + if ($pl === 0) { + return (string) ($this->_getUserPath().$this->slashify($path)); //Completely relative + } + + if ($pl === 1) { // Drive-relative + $up = (string) $this->_getUserPath(); + $ud = (string) $this->_getDrive($up); + if ($ud !== null) { + return (string) $ud.$path; + } + return (string) $up.$path; //User dir is a UNC path + } + + if ($pl === 2) { // Directory-relative + $up = (string) $this->_getUserPath(); + $ud = (string) $this->_getDrive($up); + if (($ud !== null) && StringHelper::startsWith($ud, $path)) { + return (string) ($up . $this->slashify(substr($path,2))); + } + $drive = (string) $path{0}; + $dir = (string) $this->_getDriveDirectory($drive); + + $np = (string) ""; + if ($dir !== null) { + /* When resolving a directory-relative path that refers to a + drive other than the current drive, insist that the caller + have read permission on the result */ + $p = (string) $drive . (':'.$dir.$this->slashify(substr($path,2))); + + if (!$this->checkAccess($p, false)) { + // FIXME + // throw security error + die("Can't resolve path $p"); + } + return $p; + } + return (string) $drive.':'.$this->slashify(substr($path,2)); //fake it + } + + throw new Exception("Unresolvable path: " . $path); + } + + /* -- most of the following is mapped to the functions mapped th php natives in FileSystem */ + + /* -- Attribute accessors -- */ + + function setReadOnly($f) { + // dunno how to do this on win + throw new Exception("WIN32FileSystem doesn't support read-only yet."); + } + + /* -- Filesystem interface -- */ + + protected function _access($path) { + if (!$this->checkAccess($path, false)) { + throw new Exception("Can't resolve path $p"); + } + return true; + } + + function _nativeListRoots() { + // FIXME + } + + function listRoots() { + $ds = _nativeListRoots(); + $n = 0; + for ($i = 0; $i < 26; $i++) { + if ((($ds >> $i) & 1) !== 0) { + if (!$this->access((string)( chr(ord('A') + $i) . ':' . $this->slash))) { + $ds &= ~(1 << $i); + } else { + $n++; + } + } + } + $fs = array(); + $j = (int) 0; + $slash = (string) $this->slash; + for ($i = 0; $i < 26; $i++) { + if ((($ds >> $i) & 1) !== 0) { + $fs[$j++] = new PhingFile(chr(ord('A') + $i) . ':' . $this->slash); + } + } + return $fs; + } + + /* -- Basic infrastructure -- */ + + /** compares file paths lexicographically */ + function compare(PhingFile $f1, PhingFile $f2) { + $f1Path = $f1->getPath(); + $f2Path = $f2->getPath(); + return (boolean) strcasecmp((string) $f1Path, (string) $f2Path); + } + + + /** + * returns the contents of a directory in an array + */ + function lister($f) { + $dir = @opendir($f->getAbsolutePath()); + if (!$dir) { + throw new Exception("Can't open directory " . $f->__toString()); + } + $vv = array(); + while (($file = @readdir($dir)) !== false) { + if ($file == "." || $file == "..") { + continue; + } + $vv[] = (string) $file; + } + @closedir($dir); + return $vv; + } + +} + +?> diff --git a/buildscripts/phing/classes/phing/system/io/WinNTFileSystem.php b/buildscripts/phing/classes/phing/system/io/WinNTFileSystem.php new file mode 100644 index 00000000..86f76d80 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/WinNTFileSystem.php @@ -0,0 +1,35 @@ +. + */ + +include_once 'phing/system/io/Win32FileSystem.php'; + +/** + * FileSystem for Windows NT/2000. + * @package phing.system.io + */ + +class WinNTFileSystem extends Win32FileSystem { + + /* -- class only for convenience and future use everything is inherinted --*/ + + +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/Writer.php b/buildscripts/phing/classes/phing/system/io/Writer.php new file mode 100644 index 00000000..5e1a69b9 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/Writer.php @@ -0,0 +1,48 @@ +. + */ + +/** + * Abstract class for writing character streams. + * @package phing.system.io + */ +abstract class Writer { + + abstract public function write($buf, $off = null, $len = null); + + abstract public function reset(); + + abstract public function close(); + + abstract public function open(); + + public function mark() {} + + public function ready() {} + + public function markSupported() {} + + /** + * Returns the filename, url, etc. that is being written to. + * @return string + */ + abstract function getResource(); +} +?> diff --git a/buildscripts/phing/classes/phing/system/lang/Character.php b/buildscripts/phing/classes/phing/system/lang/Character.php new file mode 100644 index 00000000..bb7a5589 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/lang/Character.php @@ -0,0 +1,49 @@ +. + */ + +/** + * @package phing.system.lang + */ +class Character { + + // this class might be extended with plenty of ordinal char constants + // and the like to support the multibyte aware datatype (char) in php + // in form of an object. + // anyway just a thought + + function isLetter($char) { + + if (strlen($char) !== 1) + $char = 0; + + $char = (int) ord($char); + + if ($char >= ord('A') && $char <= ord('Z')) + return true; + + if ($char >= ord('a') && $char <= ord('z')) + return true; + + return false; + } + +} +?> diff --git a/buildscripts/phing/classes/phing/system/lang/EventObject.php b/buildscripts/phing/classes/phing/system/lang/EventObject.php new file mode 100644 index 00000000..4a2211bc --- /dev/null +++ b/buildscripts/phing/classes/phing/system/lang/EventObject.php @@ -0,0 +1,52 @@ +. + */ + +/** + * @package phing.system.lang + */ +class EventObject { + + /** The object on which the Event initially occurred. */ + protected $source; + + /** Constructs a prototypical Event. */ + function __construct($source) { + if ($source === null) { + throw new Exception("Null source"); + } + $this->source = $source; + } + + /** The object on which the Event initially occurred. */ + function getSource() { + return $this->source; + } + + /** Returns a String representation of this EventObject.*/ + function toString() { + if (method_exists($this->source, "toString")) { + return get_class($this)."[source=".$this->source->toString()."]"; + } else { + return get_class($this)."[source=".get_class($this->source)."]"; + } + } +} +?> diff --git a/buildscripts/phing/classes/phing/system/lang/FileNotFoundException.php b/buildscripts/phing/classes/phing/system/lang/FileNotFoundException.php new file mode 100644 index 00000000..ff48c785 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/lang/FileNotFoundException.php @@ -0,0 +1,27 @@ +. + */ + +/** + * @package phing.system.lang + */ +class FileNotFoundException extends Exception {} + +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/system/lang/NullPointerException.php b/buildscripts/phing/classes/phing/system/lang/NullPointerException.php new file mode 100644 index 00000000..38fa5c10 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/lang/NullPointerException.php @@ -0,0 +1,27 @@ +. + */ + +/** + * @package phing.system.lang + */ +class NullPointerException extends Exception {} + +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/system/lang/SecurityException.php b/buildscripts/phing/classes/phing/system/lang/SecurityException.php new file mode 100644 index 00000000..21e8b1c3 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/lang/SecurityException.php @@ -0,0 +1,27 @@ +. + */ + +/** + * @package phing.system.lang + */ +class SecurityException extends Exception {} + +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/system/util/Message.php b/buildscripts/phing/classes/phing/system/util/Message.php new file mode 100644 index 00000000..bf7bb56b --- /dev/null +++ b/buildscripts/phing/classes/phing/system/util/Message.php @@ -0,0 +1,9 @@ + diff --git a/buildscripts/phing/classes/phing/system/util/Properties.php b/buildscripts/phing/classes/phing/system/util/Properties.php new file mode 100644 index 00000000..deff2cdf --- /dev/null +++ b/buildscripts/phing/classes/phing/system/util/Properties.php @@ -0,0 +1,270 @@ +. + */ + +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/system/io/FileWriter.php'; + +/** + * Convenience class for reading and writing property files. + * + * FIXME + * - Add support for arrays (separated by ',') + * + * @package phing.system.util + * @version $Revision: 1.13 $ + */ +class Properties { + + private $properties = array(); + + /** + * Load properties from a file. + * + * @param PhingFile $file + * @return void + * @throws IOException - if unable to read file. + */ + function load(PhingFile $file) { + if ($file->canRead()) { + $this->parse($file->getPath(), false); + } else { + throw new IOException("Can not read file ".$file->getPath()); + } + + } + + /** + * Replaces parse_ini_file() or better_parse_ini_file(). + * Saves a step since we don't have to parse and then check return value + * before throwing an error or setting class properties. + * + * @param string $filePath + * @param boolean $processSections Whether to honor [SectionName] sections in INI file. + * @return array Properties loaded from file (no prop replacements done yet). + */ + protected function parse($filePath) { + + // load() already made sure that file is readable + // but we'll double check that when reading the file into + // an array + + if (($lines = @file($filePath)) === false) { + throw new IOException("Unable to parse contents of $filePath"); + } + + $this->properties = array(); + $sec_name = ""; + + foreach($lines as $line) { + + $line = trim($line); + + if($line == "") + continue; + + if ($line{0} == '#' or $line{0} == ';') { + // it's a comment, so continue to next line + continue; + } else { + $pos = strpos($line, '='); + $property = trim(substr($line, 0, $pos)); + $value = trim(substr($line, $pos + 1)); + $this->properties[$property] = $this->inVal($value); + } + + } // for each line + } + + /** + * Process values when being read in from properties file. + * does things like convert "true" => true + * @param string $val Trimmed value. + * @return mixed The new property value (may be boolean, etc.) + */ + protected function inVal($val) { + if ($val === "true") { + $val = true; + } elseif ($val === "false") { + $val = false; + } + return $val; + } + + /** + * Process values when being written out to properties file. + * does things like convert true => "true" + * @param mixed $val The property value (may be boolean, etc.) + * @return string + */ + protected function outVal($val) { + if ($val === true) { + $val = "true"; + } elseif ($val === false) { + $val = "false"; + } + return $val; + } + + /** + * Create string representation that can be written to file and would be loadable using load() method. + * + * Essentially this function creates a string representation of properties that is ready to + * write back out to a properties file. This is used by store() method. + * + * @return string + */ + public function toString() { + $buf = ""; + foreach($this->properties as $key => $item) { + $buf .= $key . "=" . $this->outVal($item) . Phing::getProperty('line.separator'); + } + return $buf; + } + + /** + * Stores current properties to specified file. + * + * @param PhingFile $file File to create/overwrite with properties. + * @param string $header Header text that will be placed (within comments) at the top of properties file. + * @return void + * @throws IOException - on error writing properties file. + */ + function store(PhingFile $file, $header = null) { + // stores the properties in this object in the file denoted + // if file is not given and the properties were loaded from a + // file prior, this method stores them in the file used by load() + try { + $fw = new FileWriter($file); + $fw->open(); + if ($header !== null) { + $fw->write( "# " . $header . Phing::getProperty("line.separator") ); + } + $fw->write($this->toString()); + $fw->close(); + } catch (IOException $e) { + throw new IOException("Error writing property file: " . $e->getMessage()); + } + } + + /** + * Returns copy of internal properties hash. + * Mostly for performance reasons, property hashes are often + * preferable to passing around objects. + * + * @return array + */ + function getProperties() { + return $this->properties; + } + + /** + * Get value for specified property. + * This is the same as get() method. + * + * @param string $prop The property name (key). + * @return mixed + * @see get() + */ + function getProperty($prop) { + if (!isset($this->properties[$prop])) { + return null; + } + return $this->properties[$prop]; + } + + /** + * Get value for specified property. + * This function exists to provide a hashtable-like interface for + * properties. + * + * @param string $prop The property name (key). + * @return mixed + * @see getProperty() + */ + function get($prop) { + if (!isset($this->properties[$prop])) { + return null; + } + return $this->properties[$prop]; + } + + /** + * Set the value for a property. + * + * @param string $key + * @param mixed $value + * @return mixed Old property value or NULL if none was set. + */ + function setProperty($key, $value) { + $oldValue = @$this->properties[$key]; + $this->properties[$key] = $value; + return $oldValue; + } + + /** + * Set the value for a property. + * This function exists to provide hashtable-lie + * interface for properties. + * + * @param string $key + * @param mixed $value + */ + function put($key, $value) { + return $this->setProperty($key, $value); + } + + /** + * Same as keys() function, returns an array of property names. + * @return array + */ + function propertyNames() { + return $this->keys(); + } + + /** + * Whether loaded properties array contains specified property name. + * @return boolean + */ + function containsKey($key) { + return isset($this->properties[$key]); + } + + /** + * Returns properties keys. + * Use this for foreach() {} iterations, as this is + * faster than looping through property values. + * @return array + */ + function keys() { + return array_keys($this->properties); + } + + /** + * Whether properties list is empty. + * @return boolean + */ + function isEmpty() { + return empty($this->properties); + } + +} +?> diff --git a/buildscripts/phing/classes/phing/system/util/Register.php b/buildscripts/phing/classes/phing/system/util/Register.php new file mode 100644 index 00000000..5ef2b2fd --- /dev/null +++ b/buildscripts/phing/classes/phing/system/util/Register.php @@ -0,0 +1,115 @@ + + * + * + * + * The task/type must provide a supporting setter for the attribute: + * + * + * function setListeningReplace(RegisterSlot $slot) { + * $this->replace = $slot; + * } + * + * // in main() + * if ($this->replace instanceof RegisterSlot) { + * $this->regexp->setReplace($this->replace->getValue()); + * } else { + * $this->regexp->setReplace($this->replace); + * } + * + * + * @author Hans Lellelid + * @version $Revision: 1.3 $ + * @package phing.system.util + */ +class Register { + + /** Slots that have been registered */ + private static $slots = array(); + + /** + * Returns RegisterSlot for specified key. + * + * If not slot exists a new one is created for key. + * + * @param string $key + * @return RegisterSlot + */ + public static function getSlot($key) { + if (!isset(self::$slots[$key])) { + self::$slots[$key] = new RegisterSlot($key); + } + return self::$slots[$key]; + } +} + + +/** + * Represents a slot in the register. + */ +class RegisterSlot { + + /** The name of this slot. */ + private $key; + + /** The value for this slot. */ + private $value; + + /** + * Constructs a new RegisterSlot, setting the key to passed param. + * @param string $key + */ + public function __construct($key) { + $this->key = (string) $key; + } + + /** + * Sets the key / name for this slot. + * @param string $k + */ + public function setKey($k) { + $this->key = (string) $k; + } + + /** + * Gets the key / name for this slot. + * @return string + */ + public function getKey() { + return $this->key; + } + + /** + * Sets the value for this slot. + * @param mixed + */ + public function setValue($v) { + $this->value = $v; + } + + /** + * Returns the value at this slot. + * @return mixed + */ + public function getValue() { + return $this->value; + } + +} +?> diff --git a/buildscripts/phing/classes/phing/system/util/Timer.php b/buildscripts/phing/classes/phing/system/util/Timer.php new file mode 100644 index 00000000..a2a665b0 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/util/Timer.php @@ -0,0 +1,96 @@ +. + */ + + +/** + * This class can be used to obtain the execution time of all of the scripts + * that are executed in the process of building a page. + * + * Example: + * To be done before any scripts execute: + * + * $Timer = new Timer; + * $Timer->Start_Timer(); + * + * To be done after all scripts have executed: + * + * $timer->Stop_Timer(); + * $timer->Get_Elapsed_Time(int number_of_places); + * + * @author Charles Killian + * @author Hans Lellelid + * @package phing.system.util + * @version $Revision: 1.5 $ $Date: 2003/12/24 13:02:09 $ + */ +class Timer { + + /** start time */ + protected $stime; + + /** end time */ + protected $etime; + + /** + * This function sets the class variable $stime to the current time in + * microseconds. + * @return void + */ + public function start() { + $this->stime = $this->getMicrotime(); + } + + /** + * This function sets the class variable $etime to the current time in + * microseconds. + * @return void + */ + function stop() { + $this->etime = $this->getMicrotime(); + } + + /** + * This function returns the elapsed time in seconds. + * + * Call start_time() at the beginning of script execution and end_time() at + * the end of script execution. Then, call elapsed_time() to obtain the + * difference between start_time() and end_time(). + * + * @param $places decimal place precision of elapsed time (default is 5) + * @return string Properly formatted time. + */ + function getElapsedTime($places=5) { + $etime = $this->etime - $this->stime; + $format = "%0.".$places."f"; + return (sprintf ($format, $etime)); + } + + /** + * This function returns the current time in microseconds. + * + * @author Everett Michaud, Zend.com + * @return current time in microseconds + * @access private + */ + function getMicrotime() { + list($usec, $sec) = explode(" ", microtime()); + return ((float)$usec + (float)$sec); + } +} diff --git a/buildscripts/phing/classes/phing/tasks/defaults.properties b/buildscripts/phing/classes/phing/tasks/defaults.properties new file mode 100644 index 00000000..d0e62eff --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/defaults.properties @@ -0,0 +1,69 @@ +; ------------------------------------- +; These taskdefs are loaded at startup. +; ------------------------------------- + +; Internal system tasks +; +adhoc=phing.tasks.system.AdhocTask +adhoc-task=phing.tasks.system.AdhocTaskdefTask +adhoc-type=phing.tasks.system.AdhocTypedefTask +append=phing.tasks.system.AppendTask +available=phing.tasks.system.AvailableTask +chmod=phing.tasks.system.ChmodTask +condition=phing.tasks.system.ConditionTask +copy=phing.tasks.system.CopyTask +cvs=phing.tasks.system.CvsTask +cvspass=phing.tasks.system.CvsPassTask +delete=phing.tasks.system.DeleteTask +echo=phing.tasks.system.EchoTask +exec=phing.tasks.system.ExecTask +fail=phing.tasks.system.ExitTask +foreach=phing.tasks.system.ForeachTask +includepath=phing.tasks.system.IncludePathTask +input=phing.tasks.system.InputTask +mkdir=phing.tasks.system.MkdirTask +move=phing.tasks.system.MoveTask +phing=phing.tasks.system.PhingTask +phingcall=phing.tasks.system.PhingCallTask +php=phing.tasks.system.PhpEvalTask +property=phing.tasks.system.PropertyTask +propertyprompt=phing.tasks.system.PropertyPromptTask +reflexive=phing.tasks.system.ReflexiveTask +resolvepath=phing.tasks.system.ResolvePathTask +taskdef=phing.tasks.system.TaskdefTask +touch=phing.tasks.system.TouchTask +tstamp=phing.tasks.system.TstampTask +typedef=phing.tasks.system.TypedefTask +uptodate=phing.tasks.system.UpToDateTask +xslt=phing.tasks.system.XsltTask +if=phing.tasks.system.IfTask +warn=phing.tasks.system.WarnTask + +; "Core" contributed tasks +; -- i.e. no taskdef needed. + +sql=phing.tasks.ext.CreoleSQLExecTask +package-as-path=phing.tasks.ext.PackageAsPathTask +smarty=phing.tasks.ext.SmartyTask +capsule=phing.tasks.ext.CapsuleTask +tar=phing.tasks.ext.TarTask +pearpkg=phing.tasks.ext.PearPackageTask +mail=phing.tasks.ext.MailTask +zip=phing.tasks.ext.ZipTask +phplint=phing.tasks.ext.PhpLintTask + +; "ext" tasks +phpdoc=phing.tasks.ext.phpdoc.PHPDocumentorTask +svnlastrevision=phing.tasks.ext.svn.SvnLastRevisionTask +svnexport=phing.tasks.ext.svn.SvnExportTask +phpunit2=phing.tasks.ext.phpunit2.PHPUnit2Task +phpunit2report=phing.tasks.ext.phpunit2.PHPUnit2ReportTask +coverage-setup=phing.tasks.ext.coverage.CoverageSetupTask +coverage-merger=phing.tasks.ext.coverage.CoverageMergerTask +coverage-report=phing.tasks.ext.coverage.CoverageReportTask +ioncubeencoder=phing.tasks.ext.ioncube.IoncubeEncoderTask +ioncubelicense=phing.tasks.ext.ioncube.IoncubeLicenseTask +simpletest=phing.tasks.ext.simpletest.SimpleTestTask +phplint=phing.tasks.ext.PhpLintTask +xmllint=phing.tasks.ext.XmlLintTask +analyze=phing.tasks.ext.ZendCodeAnalyzerTask \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/CapsuleTask.php b/buildscripts/phing/classes/phing/tasks/ext/CapsuleTask.php new file mode 100644 index 00000000..aa43a0e4 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/CapsuleTask.php @@ -0,0 +1,478 @@ +. + */ + +include_once 'phing/Task.php'; +include_once 'phing/BuildException.php'; +include_once 'phing/lib/Capsule.php'; +include_once 'phing/util/StringHelper.php'; + +/** + * A phing task for generating output by using Capsule. + * + * This is based on the interface to TexenTask from Apache's Velocity engine. + * + * @author Hans Lellelid + * @version $Revision: 1.17 $ + * @package phing.tasks.ext + */ +class CapsuleTask extends Task { + + /** + * Capsule "template" engine. + * @var Capsule + */ + protected $context; + + /** + * Any vars assigned via the build file. + * @var array AssignedVar[] + */ + protected $assignedVars = array(); + + /** + * This is the control template that governs the output. + * It may or may not invoke the services of worker + * templates. + * @var string + */ + protected $controlTemplate; + + /** + * This is where Velocity will look for templates + * using the file template loader. + * @var string + */ + protected $templatePath; + + /** + * This is where texen will place all the output + * that is a product of the generation process. + * @var string + */ + protected $outputDirectory; + + /** + * This is the file where the generated text + * will be placed. + * @var string + */ + protected $outputFile; + + /** + *

                                                + * These are properties that are fed into the + * initial context from a properties file. This + * is simply a convenient way to set some values + * that you wish to make available in the context. + *

                                                + *

                                                + * These values are not critical, like the template path + * or output path, but allow a convenient way to + * set a value that may be specific to a particular + * generation task. + *

                                                + *

                                                + * For example, if you are generating scripts to allow + * user to automatically create a database, then + * you might want the $databaseName + * to be placed + * in the initial context so that it is available + * in a script that might look something like the + * following: + *

                                                +     * #!bin/sh
                                                +     * 
                                                +     * echo y | mysqladmin create $databaseName
                                                +     * 
                                                + * The value of $databaseName isn't critical to + * output, and you obviously don't want to change + * the ant task to simply take a database name. + * So initial context values can be set with + * properties file. + * + * @var array + */ + protected $contextProperties; + + // ----------------------------------------------------------------------- + // The following getters & setters are used by phing to set properties + // specified in the XML for the capsule task. + // ----------------------------------------------------------------------- + + /** + * [REQUIRED] Set the control template for the + * generating process. + * @param string $controlTemplate + * @return void + */ + public function setControlTemplate ($controlTemplate) { + $this->controlTemplate = $controlTemplate; + } + + /** + * Get the control template for the + * generating process. + * @return string + */ + public function getControlTemplate() { + return $this->controlTemplate; + } + + /** + * [REQUIRED] Set the path where Velocity will look + * for templates using the file template + * loader. + * @return void + * @throws Exception + */ + public function setTemplatePath($templatePath) { + $resolvedPath = ""; + $tok = strtok($templatePath, ","); + while ( $tok ) { + // resolve relative path from basedir and leave + // absolute path untouched. + $fullPath = $this->project->resolveFile($tok); + $cpath = $fullPath->getCanonicalPath(); + if ($cpath === false) { + $this->log("Template directory does not exist: " . $fullPath->getAbsolutePath()); + } else { + $resolvedPath .= $cpath; + } + $tok = strtok(","); + if ( $tok ) { + $resolvedPath .= ","; + } + } + $this->templatePath = $resolvedPath; + } + + /** + * Get the path where Velocity will look + * for templates using the file template + * loader. + * @return string + */ + public function getTemplatePath() { + return $this->templatePath; + } + + /** + * [REQUIRED] Set the output directory. It will be + * created if it doesn't exist. + * @param PhingFile $outputDirectory + * @return void + * @throws Exception + */ + public function setOutputDirectory(PhingFile $outputDirectory) { + try { + if (!$outputDirectory->exists()) { + $this->log("Output directory does not exist, creating: " . $outputDirectory->getPath(),PROJECT_MSG_VERBOSE); + if (!$outputDirectory->mkdirs()) { + throw new IOException("Unable to create Ouptut directory: " . $outputDirectory->getAbsolutePath()); + } + } + $this->outputDirectory = $outputDirectory->getCanonicalPath(); + } catch (IOException $ioe) { + throw new BuildException($ioe); + } + } + + /** + * Get the output directory. + * @return string + */ + public function getOutputDirectory() { + return $this->outputDirectory; + } + + /** + * [REQUIRED] Set the output file for the + * generation process. + * @param string $outputFile (TODO: change this to File) + * @return void + */ + public function setOutputFile($outputFile) { + $this->outputFile = $outputFile; + } + + /** + * Get the output file for the + * generation process. + * @return string + */ + public function getOutputFile() { + return $this->outputFile; + } + + /** + * Set the context properties that will be + * fed into the initial context be the + * generating process starts. + * @param string $file + * @return void + */ + public function setContextProperties($file) { + $sources = explode(",", $file); + $this->contextProperties = new Properties(); + + // Always try to get the context properties resource + // from a file first. Templates may be taken from a JAR + // file but the context properties resource may be a + // resource in the filesystem. If this fails than attempt + // to get the context properties resource from the + // classpath. + for ($i=0, $sourcesLength=count($sources); $i < $sourcesLength; $i++) { + $source = new Properties(); + + try { + + // resolve relative path from basedir and leave + // absolute path untouched. + $fullPath = $this->project->resolveFile($sources[$i]); + $this->log("Using contextProperties file: " . $fullPath->toString()); + $source->load($fullPath); + + } catch (Exception $e) { + + throw new BuildException("Context properties file " . $sources[$i] . + " could not be found in the file system!"); + + } + + $keys = $source->keys(); + + foreach ($keys as $key) { + $name = $key; + $value = $this->project->replaceProperties($source->getProperty($name)); + $this->contextProperties->setProperty($name, $value); + } + } + } + + /** + * Get the context properties that will be + * fed into the initial context be the + * generating process starts. + * @return Properties + */ + public function getContextProperties() { + return $this->contextProperties; + } + + /** + * Creates an "AssignedVar" class. + */ + public function createAssign() { + $a = new AssignedVar(); + $this->assignedVars[] = $a; + return $a; + } + + // --------------------------------------------------------------- + // End of XML setters & getters + // --------------------------------------------------------------- + + /** + * Creates a Smarty object. + * + * @return Smarty initialized (cleared) Smarty context. + * @throws Exception the execute method will catch + * and rethrow as a BuildException + */ + public function initControlContext() { + $this->context->clear(); + foreach($this->assignedVars as $var) { + $this->context->put($var->getName(), $var->getValue()); + } + return $this->context; + } + + /** + * Execute the input script with Velocity + * + * @throws BuildException + * BuildExceptions are thrown when required attributes are missing. + * Exceptions thrown by Velocity are rethrown as BuildExceptions. + */ + public function main() { + + // Make sure the template path is set. + if (empty($this->templatePath)) { + throw new BuildException("The template path needs to be defined!"); + } + + // Make sure the control template is set. + if ($this->controlTemplate === null) { + throw new BuildException("The control template needs to be defined!"); + } + + // Make sure the output directory is set. + if ($this->outputDirectory === null) { + throw new BuildException("The output directory needs to be defined!"); + } + + // Make sure there is an output file. + if ($this->outputFile === null) { + throw new BuildException("The output file needs to be defined!"); + } + + // Setup Smarty runtime. + + // Smarty uses one object to store properties and to store + // the context for the template (unlike Velocity). We setup this object, calling it + // $this->context, and then initControlContext simply zeros out + // any assigned variables. + $this->context = new Capsule(); + + if ($this->templatePath !== null) { + $this->log("Using templatePath: " . $this->templatePath); + $this->context->setTemplatePath($this->templatePath); + } + + // Make sure the output directory exists, if it doesn't + // then create it. + $outputDir = new PhingFile($this->outputDirectory); + if (!$outputDir->exists()) { + $this->log("Output directory does not exist, creating: " . $outputDir->getAbsolutePath()); + $outputDir->mkdirs(); + } + + $this->context->setOutputDirectory($outputDir->getAbsolutePath()); + + $path = $this->outputDirectory . DIRECTORY_SEPARATOR . $this->outputFile; + $this->log("Generating to file " . $path); + + //$writer = new FileWriter($path); + + // The generator and the output path should + // be placed in the init context here and + // not in the generator class itself. + $c = $this->initControlContext(); + + // Set any variables that need to always + // be loaded + $this->populateInitialContext($c); + + // Feed all the options into the initial + // control context so they are available + // in the control/worker templates. + if ($this->contextProperties !== null) { + + foreach($this->contextProperties->keys() as $property) { + + $value = $this->contextProperties->getProperty($property); + + // Special exception (from Texen) + // for properties ending in file.contents: + // in that case we dump the contents of the file + // as the "value" for the Property. + if (preg_match('/file\.contents$/', $property)) { + // pull in contents of file specified + + $property = substr($property, 0, strpos($property, "file.contents") - 1); + + // reset value, and then + // read in teh contents of the file into that var + $value = ""; + $f = new PhingFile($project->resolveFile($value)->getCanonicalPath()); + if ($f->exists()) { + $fr = new FileReader($f); + $fr->readInto($value); + } + + } // if ends with file.contents + + if (StringHelper::isBoolean($value)) { + $value = StringHelper::booleanValue($value); + } + + $c->put($property, $value); + + } // foreach property + + } // if contextProperties !== null + + try { + $this->log("Parsing control template: " . $this->controlTemplate); + $c->parse($this->controlTemplate, $path); + } catch (Exception $ioe) { + throw new BuildException("Cannot write parsed template: ". $ioe->getMessage()); + } + + $this->cleanup(); + } + + /** + * Place useful objects into the initial context. + * + * + * @param Capsule $context The context to populate, as retrieved from + * {@link #initControlContext()}. + * @return void + * @throws Exception Error while populating context. The {@link + * #main()} method will catch and rethrow as a + * BuildException. + */ + protected function populateInitialContext(Capsule $context) { + $this->context->put("now", strftime("%c", time())); + $this->context->put("task", $this); + } + + /** + * A hook method called at the end of {@link #execute()} which can + * be overridden to perform any necessary cleanup activities (such + * as the release of database connections, etc.). By default, + * does nothing. + * @return void + * @throws Exception Problem cleaning up. + */ + protected function cleanup() { + } +} + + +/** + * An "inner" class for holding assigned var values. + * May be need to expand beyond name/value in the future. + */ +class AssignedVar { + + private $name; + private $value; + + function setName($v) { + $this->name = $v; + } + + function setValue($v) { + $this->value = $v; + } + + function getName() { + return $this->name; + } + + function getValue() { + return $this->value; + } + +} \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/CreoleSQLExecTask.php b/buildscripts/phing/classes/phing/tasks/ext/CreoleSQLExecTask.php new file mode 100644 index 00000000..d35e44f4 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/CreoleSQLExecTask.php @@ -0,0 +1,556 @@ +. + */ + +require_once 'phing/tasks/ext/CreoleTask.php'; +include_once 'phing/system/io/StringReader.php'; + +/** + * Executes a series of SQL statements on a database using Creole. + * + *

                                                Statements can + * either be read in from a text file using the src attribute or from + * between the enclosing SQL tags.

                                                + * + *

                                                Multiple statements can be provided, separated by semicolons (or the + * defined delimiter). Individual lines within the statements can be + * commented using either --, // or REM at the start of the line.

                                                + * + *

                                                The autocommit attribute specifies whether auto-commit should be + * turned on or off whilst executing the statements. If auto-commit is turned + * on each statement will be executed and committed. If it is turned off the + * statements will all be executed as one transaction.

                                                + * + *

                                                The onerror attribute specifies how to proceed when an error occurs + * during the execution of one of the statements. + * The possible values are: continue execution, only show the error; + * stop execution and commit transaction; + * and abort execution and transaction and fail task.

                                                + * + * @author Hans Lellelid (Phing) + * @author Jeff Martin (Ant) + * @author Michael McCallum (Ant) + * @author Tim Stephenson (Ant) + * @package phing.tasks.ext + * @version $Revision: 1.21 $ + */ +class CreoleSQLExecTask extends CreoleTask { + + private $goodSql = 0; + private $totalSql = 0; + + const DELIM_ROW = "row"; + const DELIM_NORMAL = "normal"; + + /** + * Database connection + */ + private $conn = null; + + /** + * files to load + */ + private $filesets = array(); + + /** + * SQL statement + */ + private $statement = null; + + /** + * SQL input file + */ + private $srcFile = null; + + /** + * SQL input command + */ + private $sqlCommand = ""; + + /** + * SQL transactions to perform + */ + private $transactions = array(); + + /** + * SQL Statement delimiter + */ + private $delimiter = ";"; + + /** + * The delimiter type indicating whether the delimiter will + * only be recognized on a line by itself + */ + private $delimiterType = "normal"; // can't use constant just defined + + /** + * Print SQL results. + */ + private $print = false; + + /** + * Print header columns. + */ + private $showheaders = true; + + /** + * Results Output file. + */ + private $output = null; + + + /** + * Action to perform if an error is found + **/ + private $onError = "abort"; + + /** + * Encoding to use when reading SQL statements from a file + */ + private $encoding = null; + + /** + * Append to an existing file or overwrite it? + */ + private $append = false; + + /** + * Set the name of the SQL file to be run. + * Required unless statements are enclosed in the build file + */ + public function setSrc(PhingFile $srcFile) { + $this->srcFile = $srcFile; + } + + /** + * Set an inline SQL command to execute. + * NB: Properties are not expanded in this text. + */ + public function addText($sql) { + $this->sqlCommand .= $sql; + } + + /** + * Adds a set of files (nested fileset attribute). + */ + public function addFileset(FileSet $set) { + $this->filesets[] = $set; + } + + /** + * Add a SQL transaction to execute + */ + public function createTransaction() { + $t = new SQLExecTransaction($this); + $this->transactions[] = $t; + return $t; + } + + /** + * Set the file encoding to use on the SQL files read in + * + * @param encoding the encoding to use on the files + */ + public function setEncoding($encoding) { + $this->encoding = $encoding; + } + + /** + * Set the statement delimiter. + * + *

                                                For example, set this to "go" and delimitertype to "ROW" for + * Sybase ASE or MS SQL Server.

                                                + * + * @param delimiter + */ + public function setDelimiter($delimiter) + { + $this->delimiter = $delimiter; + } + + /** + * Set the Delimiter type for this sql task. The delimiter type takes two + * values - normal and row. Normal means that any occurence of the delimiter + * terminate the SQL command whereas with row, only a line containing just + * the delimiter is recognized as the end of the command. + * + * @param string $delimiterType + */ + public function setDelimiterType($delimiterType) + { + $this->delimiterType = $delimiterType; + } + + /** + * Set the print flag. + * + * @param boolean $print + */ + public function setPrint($print) + { + $this->print = (boolean) $print; + } + + /** + * Print headers for result sets from the + * statements; optional, default true. + * @param boolean $showheaders + */ + public function setShowheaders($showheaders) { + $this->showheaders = (boolean) $showheaders; + } + + /** + * Set the output file; + * optional, defaults to the console. + * @param PhingFile $output + */ + public function setOutput(PhingFile $output) { + $this->output = $output; + } + + /** + * whether output should be appended to or overwrite + * an existing file. Defaults to false. + * @param $append + */ + public function setAppend($append) { + $this->append = (boolean) $append; + } + + + /** + * Action to perform when statement fails: continue, stop, or abort + * optional; default "abort" + */ + public function setOnerror($action) { + $this->onError = $action; + } + + /** + * Load the sql file and then execute it + * @throws BuildException + */ + public function main() { + + $savedTransaction = array(); + for($i=0,$size=count($this->transactions); $i < $size; $i++) { + $savedTransaction[] = clone $this->transactions[$i]; + } + + $savedSqlCommand = $this->sqlCommand; + + $this->sqlCommand = trim($this->sqlCommand); + + try { + if ($this->srcFile === null && $this->sqlCommand === "" + && empty($this->filesets)) { + if (count($this->transactions) === 0) { + throw new BuildException("Source file or fileset, " + . "transactions or sql statement " + . "must be set!", $this->location); + } + } + + if ($this->srcFile !== null && !$this->srcFile->exists()) { + throw new BuildException("Source file does not exist!", $this->location); + } + + // deal with the filesets + for ($i = 0,$size=count($this->filesets); $i < $size; $i++) { + $fs = $this->filesets[$i]; + $ds = $fs->getDirectoryScanner($this->project); + $srcDir = $fs->getDir($this->project); + + $srcFiles = $ds->getIncludedFiles(); + + // Make a transaction for each file + for ($j=0, $size=count($srcFiles); $j < $size; $j++) { + $t = $this->createTransaction(); + $t->setSrc(new PhingFile($srcDir, $srcFiles[$j])); + } + } + + // Make a transaction group for the outer command + $t = $this->createTransaction(); + if ($this->srcFile) $t->setSrc($this->srcFile); + $t->addText($this->sqlCommand); + $this->conn = $this->getConnection(); + + try { + + $this->statement = $this->conn->createStatement(); + + $out = null; + + try { + + if ($this->output !== null) { + $this->log("Opening output file " . $this->output, PROJECT_MSG_VERBOSE); + $out = new BufferedWriter(new FileWriter($this->output->getAbsolutePath(), $this->append)); + } + + // Process all transactions + for ($i=0,$size=count($this->transactions); $i < $size; $i++) { + $this->transactions[$i]->runTransaction($out); + if (!$this->isAutocommit()) { + $this->log("Commiting transaction", PROJECT_MSG_VERBOSE); + $this->conn->commit(); + } + } + if ($out) $out->close(); + } catch (Exception $e) { + if ($out) $out->close(); + throw $e; + } + } catch (IOException $e) { + if (!$this->isAutocommit() && $this->conn !== null && $this->onError == "abort") { + try { + $this->conn->rollback(); + } catch (SQLException $ex) {} + } + throw new BuildException($e->getMessage(), $this->location); + } catch (SQLException $e){ + if (!$this->isAutocommit() && $this->conn !== null && $this->onError == "abort") { + try { + $this->conn->rollback(); + } catch (SQLException $ex) {} + } + throw new BuildException($e->getMessage(), $this->location); + } + + $this->log($this->goodSql . " of " . $this->totalSql . + " SQL statements executed successfully"); + } catch (Exception $e) { + $this->transactions = $savedTransaction; + $this->sqlCommand = $savedSqlCommand; + throw $e; + } + // finally { + $this->transactions = $savedTransaction; + $this->sqlCommand = $savedSqlCommand; + + } + + + /** + * read in lines and execute them + * @throws SQLException, IOException + */ + public function runStatements(Reader $reader, $out = null) { + $sql = ""; + $line = ""; + $in = new BufferedReader($reader); + try { + while (($line = $in->readLine()) !== null) { + $line = trim($line); + $line = ProjectConfigurator::replaceProperties($this->project, $line, + $this->project->getProperties()); + + if (StringHelper::startsWith("//", $line) || + StringHelper::startsWith("--", $line) || + StringHelper::startsWith("#", $line)) { + continue; + } + + if (strlen($line) > 4 + && strtoupper(substr($line,0, 4)) == "REM ") { + continue; + } + + $sql .= " " . $line; + $sql = trim($sql); + + // SQL defines "--" as a comment to EOL + // and in Oracle it may contain a hint + // so we cannot just remove it, instead we must end it + if (strpos($line, "--") !== false) { + $sql .= "\n"; + } + + if ($this->delimiterType == self::DELIM_NORMAL + && StringHelper::endsWith($this->delimiter, $sql) + || $this->delimiterType == self::DELIM_ROW + && $line == $this->delimiter) { + $this->log("SQL: " . $sql, PROJECT_MSG_VERBOSE); + $this->execSQL(StringHelper::substring($sql, 0, strlen($sql) - strlen($this->delimiter)) - 1, $out); + $sql = ""; + } + } + + // Catch any statements not followed by ; + if ($sql !== "") { + $this->execSQL($sql, $out); + } + } catch (SQLException $e) { + throw new BuildException("Error running statements", $e); + } + } + + + /** + * Exec the sql statement. + * @throws SQLException + */ + protected function execSQL($sql, $out = null) { + // Check and ignore empty statements + if (trim($sql) == "") { + return; + } + + try { + $this->totalSql++; + if (!$this->statement->execute($sql)) { + $this->log($this->statement->getUpdateCount() . " rows affected", PROJECT_MSG_VERBOSE); + } else { + if ($this->print) { + $this->printResults($out); + } + } + + $this->goodSql++; + + } catch (SQLException $e) { + $this->log("Failed to execute: " . $sql, PROJECT_MSG_ERR); + if ($this->onError != "continue") { + throw new BuildException("Failed to execute SQL", $e); + } + $this->log($e->getMessage(), PROJECT_MSG_ERR); + } + } + + /** + * print any results in the statement. + * @throw SQLException + */ + protected function printResults($out = null) { + $lSep = Phing::getProperty('line.separator'); + $rs = null; + do { + $rs = $this->statement->getResultSet(); + + if ($rs !== null) { + + $this->log("Processing new result set.", PROJECT_MSG_VERBOSE); + + $line = ""; + + $colsprinted = false; + + while ($rs->next()) { + $fields = $rs->getRow(); + + if (!$colsprinted && $this->showheaders) { + $first = true; + foreach($fields as $fieldName => $ignore) { + if ($first) $first = false; else $line .= ","; + $line .= $fieldName; + } + if ($out !== null) { + $out->write($line); + $out->newLine(); + } else { + print($line.$lSep); + } + $line = ""; + $colsprinted = true; + } // if show headers + + $first = true; + foreach($fields as $columnValue) { + + if ($columnValue != null) { + $columnValue = trim($columnValue); + } + + if ($first) { + $first = false; + } else { + $line .= ","; + } + $line .= $columnValue; + } + + if ($out !== null) { + $out->write($line); + $out->newLine(); + } else { + print($line . $lSep); + } + $line = ""; + + } // while rs->next() + } + } while ($this->statement->getMoreResults()); + print($lSep); + if ($out !== null) $out->newLine(); + } +} + + +/** + * "Inner" class that contains the definition of a new transaction element. + * Transactions allow several files or blocks of statements + * to be executed using the same JDBC connection and commit + * operation in between. + */ +class SQLExecTransaction { + + private $tSrcFile = null; + private $tSqlCommand = ""; + private $parent; + + function __construct($parent) + { + // Parent is required so that we can log things ... + $this->parent = $parent; + } + + public function setSrc(PhingFile $src) + { + $this->tSrcFile = $src; + } + + public function addText($sql) + { + $this->tSqlCommand .= $sql; + } + + /** + * @throws IOException, SQLException + */ + public function runTransaction($out = null) + { + if (!empty($this->tSqlCommand)) { + $this->parent->log("Executing commands", PROJECT_MSG_INFO); + $this->parent->runStatements(new StringReader($this->tSqlCommand), $out); + } + + if ($this->tSrcFile !== null) { + $this->parent->log("Executing file: " . $this->tSrcFile->getAbsolutePath(), + PROJECT_MSG_INFO); + $reader = new FileReader($this->tSrcFile); + $this->parent->runStatements($reader, $out); + $reader->close(); + } + } +} + + diff --git a/buildscripts/phing/classes/phing/tasks/ext/CreoleTask.php b/buildscripts/phing/classes/phing/tasks/ext/CreoleTask.php new file mode 100644 index 00000000..a1b439e5 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/CreoleTask.php @@ -0,0 +1,242 @@ +. + */ + +require_once 'phing/Task.php'; +include_once 'phing/types/Reference.php'; + +/** + * Handles Creole configuration needed by SQL type tasks. + * + * @author Hans Lellelid (Phing) + * @author Nick Chalko (Ant) + * @author Jeff Martin (Ant) + * @author Michael McCallum (Ant) + * @author Tim Stephenson (Ant) + * @version $Revision: 1.13 $ + * @package phing.tasks.system + */ +abstract class CreoleTask extends Task { + + /** + * Used for caching loaders / driver. This is to avoid + * getting an OutOfMemoryError when calling this task + * multiple times in a row. + * + * NOT IMPLEMENTED YET + */ + private static $loaderMap = array(); + + private $caching = true; + + /** + * Autocommit flag. Default value is false + */ + private $autocommit = false; + + /** + * [optional] Classpath to Creole driver to use. + * @param string + */ + private $driver; + + /** + * DB url. + */ + private $url; + + /** + * User name. + */ + private $userId; + + /** + * Password + */ + private $password; + + /** + * RDBMS Product needed for this SQL. + **/ + private $rdbms; + + /** + * Initialize CreoleTask. + * This method includes any necessary Creole libraries and triggers + * appropriate error if they cannot be found. This is not done in header + * because we may want this class to be loaded w/o triggering an error. + */ + function init() { + include_once 'creole/Creole.php'; + if (!class_exists('Creole')) { + throw new Exception("Creole task depends on Creole classes being on include_path. (i.e. include of 'creole/Creole.php' failed.)"); + } + } + + /** + * Caching loaders / driver. This is to avoid + * getting an OutOfMemoryError when calling this task + * multiple times in a row; default: true + * @param $enable + */ + public function setCaching($enable) { + $this->caching = $enable; + } + + /** + * Sets the database connection URL; required. + * @param url The url to set + */ + public function setUrl($url) { + $this->url = $url; + } + + /** + * Set the Creole driver to be used. + * + * @param string $driver driver class name + */ + public function setDriver($driver) + { + $this->driver = $driver; + } + + /** + * Sets the password; required. + * @param password The password to set + */ + public function setPassword($password) { + $this->password = $password; + } + + /** + * Auto commit flag for database connection; + * optional, default false. + * @param autocommit The autocommit to set + */ + public function setAutocommit($autocommit) { + $this->autocommit = $autocommit; + } + + /** + * Sets the version string, execute task only if + * rdbms version match; optional. + * @param version The version to set + */ + public function setVersion($version) { + $this->version = $version; + } + + protected function getLoaderMap() { + return self::$loaderMap; + } + + + /** + * Creates a new Connection as using the driver, url, userid and password specified. + * The calling method is responsible for closing the connection. + * @return Connection the newly created connection. + * @throws BuildException if the UserId/Password/Url is not set or there is no suitable driver or the driver fails to load. + */ + protected function getConnection() { + + if ($this->url === null) { + throw new BuildException("Url attribute must be set!", $this->location); + } + + try { + + $this->log("Connecting to " . $this->getUrl(), PROJECT_MSG_VERBOSE); + $info = new Properties(); + + $dsn = Creole::parseDSN($this->url); + + if (!isset($dsn["username"]) && $this->userId === null) { + throw new BuildException("Username must be in URL or userid attribute must be set.", $this->location); + } + + if ($this->userId) { + $dsn["username"] = $this->getUserId(); + } + + if ($this->password) { + $dsn["password"] = $this->getPassword(); + } + + if ($this->driver) { + Creole::registerDriver($dsn['phptype'], $this->driver); + } + + $conn = Creole::getConnection($dsn); + $conn->setAutoCommit($this->autocommit); + return $conn; + + } catch (SQLException $e) { + throw new BuildException($e->getMessage(), $this->location); + } + + } + + public function isCaching($value) { + $this->caching = $value; + } + + /** + * Gets the autocommit. + * @return Returns a boolean + */ + public function isAutocommit() { + return $this->autocommit; + } + + /** + * Gets the url. + * @return Returns a String + */ + public function getUrl() { + return $this->url; + } + + /** + * Gets the userId. + * @return Returns a String + */ + public function getUserId() { + return $this->userId; + } + + /** + * Set the user name for the connection; required. + * @param userId The userId to set + */ + public function setUserid($userId) { + $this->userId = $userId; + } + + /** + * Gets the password. + * @return Returns a String + */ + public function getPassword() { + return $this->password; + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/ext/MailTask.php b/buildscripts/phing/classes/phing/tasks/ext/MailTask.php new file mode 100644 index 00000000..16d29fb8 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/MailTask.php @@ -0,0 +1,77 @@ +. + */ + +include_once 'phing/Task.php'; + +/** + * Send a message by mail() + * + * The build process is a success... + * + * @author Francois Harvey at SecuriWeb (http://www.securiweb.net) + * @version $Revision: 1.1 $ + * @package phing.tasks.ext + */ +class MailTask extends Task { + + protected $recipient; + + protected $subject; + + protected $msg; + + function main() { + $this->log('Sending mail to ' . $this->recipient ); + mail($this->recipient, $this->subject, $this->msg); + } + + /** setter for message */ + function setMsg($msg) { + $this->setMessage($msg); + } + + /** alias setter */ + function setMessage($msg) { + $this->msg = (string) $msg; + } + + /** setter for subject **/ + function setSubject($subject) { + $this->subject = (string) $subject; + } + + /** setter for recipient **/ + function setRecipient($recipient) { + $this->recipient = (string) $recipient; + } + + /** alias for recipient **/ + function setTo($recipient) { + $this->recipient = (string) $recipient; + } + + /** Supporting the Message syntax. */ + function addText($msg) + { + $this->msg = (string) $msg; + } +} + diff --git a/buildscripts/phing/classes/phing/tasks/ext/PackageAsPathTask.php b/buildscripts/phing/classes/phing/tasks/ext/PackageAsPathTask.php new file mode 100644 index 00000000..b8664aac --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/PackageAsPathTask.php @@ -0,0 +1,65 @@ +. + */ + +require_once 'phing/Task.php'; + +/** + * Convert dot-notation packages to relative paths. + * + * @author Hans Lellelid + * @version $Revision: 1.5 $ + * @package phing.tasks.ext + */ +class PackageAsPathTask extends Task { + + /** The package to convert. */ + protected $pckg; + + /** The value to store the conversion in. */ + protected $name; + + /** + * Executes the package to patch converstion and stores it + * in the user property value. + */ + public function main() + { + $this->project->setUserProperty($this->name, strtr($this->pckg, '.', '/')); + } + + /** + * @param string $pckg the package to convert + */ + public function setPackage($pckg) + { + $this->pckg = $pckg; + } + + /** + * @param string $name the Ant variable to store the path in + */ + public function setName($name) + { + $this->name = $name; + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/ext/PearPackageTask.php b/buildscripts/phing/classes/phing/tasks/ext/PearPackageTask.php new file mode 100644 index 00000000..4f8ee3ab --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/PearPackageTask.php @@ -0,0 +1,421 @@ +. + */ + +require_once 'phing/tasks/system/MatchingTask.php'; +include_once 'phing/types/FileSet.php'; + +/** + * A task to create PEAR package.xml file. + * + * This class uses the PEAR_PackageFileMaintainer class to perform the work. + * + * This class is designed to be very flexible -- i.e. account for changes to the package.xml w/o + * requiring changes to this class. We've accomplished this by having generic
                                                - %s(line %d): %s + * oneline-comment - One-line comment ends with ?> tag. + * bool-assign - Assignment seen where boolean expression is expected. Did you mean '==' instead of '='? + * bool-print - Print statement used when boolean expression is expected. + * bool-array - Array used when boolean expression is expected. + * bool-object - Object used when boolean expression is expected. + * call-time-ref - Call-time reference is deprecated. Define function as accepting parameter by reference instead. + * if-if-else - In if-if-else construction else relates to the closest if. Use braces to make the code clearer. + * define-params - define() requires two or three parameters. + * define-const - First parameter for define() should be string. Maybe you forgot quotes? + * break-var - Break/continue with variable is dangerous - break level can be out of scope. + * break-depth - Break/continue with depth more than current nesting level. + * var-once - Variable '%s' encountered only once. May be a typo? + * var-arg-unused - Function argument '%s' is never used. + * var-global-unused - Global variable '%s' is defined but never used. + * var-use-before-def - Variable '%s' is used before it was assigned. + * var-use-before-def-global - Global variable '%s' is used without being assigned. You are probably relying on register_globals feature of PHP. Note that this feature is off by default. + * var-no-global - PHP global variable '%s' is used as local. Maybe you wanted to define '%s' as global? + * var-value-unused - Value assigned to variable '%s' is never used + * var-ref-notmodified - Function parameter '%s' is passed by reference but never modified. Consider passing by value. + * return-empty-val - Function '%s' has both empty return and return with value. + * return-empty-used - Function '%s' has empty return but return value is used. + * return-noref - Function '%s' returns reference but the value is not assigned by reference. Maybe you meant '=&' instead of '='? + * return-end-used - Control reaches the end of function '%s'(file %s, line %d) but return value is used. + * sprintf-miss-args - Missing arguments for sprintf: format reqires %d arguments but %d are supplied. + * sprintf-extra-args - Extra arguments for sprintf: format reqires %d arguments but %d are supplied. + * unreach-code - Unreachable code in function '%s'. + * include-var - include/require with user-accessible variable can be dangerous. Consider using constant instead. + * non-object - Variable '%s' used as object, but has different type. + * bad-escape - Bad escape sequence: \%c, did you mean \\%c? + * empty-cond - Condition without a body + * expr-unused - Expression result is never used + * + * @author Knut Urdalen + * @package phing.tasks.ext + */ +class ZendCodeAnalyzerTask extends Task { + + protected $analyzerPath = ""; // Path to ZendCodeAnalyzer binary + protected $file = ""; // the source file (from xml attribute) + protected $filesets = array(); // all fileset objects assigned to this task + protected $warnings = array(); + protected $counter = 0; + protected $disable = array(); + protected $enable = array(); + + /** + * File to be analyzed + * + * @param PhingFile $file + */ + public function setFile(PhingFile $file) { + $this->file = $file; + } + + /** + * Path to ZendCodeAnalyzer binary + * + * @param string $analyzerPath + */ + public function setAnalyzerPath($analyzerPath) { + $this->analyzerPath = $analyzerPath; + } + + /** + * Disable warning levels. Seperate warning levels with ',' + * + * @param string $disable + */ + public function setDisable($disable) { + $this->disable = explode(",", $disable); + } + + /** + * Enable warning levels. Seperate warning levels with ',' + * + * @param string $enable + */ + public function setEnable($enable) { + $this->enable = explode(",", $enable); + } + + /** + * Nested creator, creates a FileSet for this task + * + * @return FileSet The created fileset object + */ + function createFileSet() { + $num = array_push($this->filesets, new FileSet()); + return $this->filesets[$num-1]; + } + + /** + * Analyze against PhingFile or a FileSet + */ + public function main() { + if(!isset($this->analyzerPath)) { + throw new BuildException("Missing attribute 'analyzerPath'"); + } + if(!isset($this->file) and count($this->filesets) == 0) { + throw new BuildException("Missing either a nested fileset or attribute 'file' set"); + } + + if($this->file instanceof PhingFile) { + $this->analyze($this->file->getPath()); + } else { // process filesets + $project = $this->getProject(); + foreach($this->filesets as $fs) { + $ds = $fs->getDirectoryScanner($project); + $files = $ds->getIncludedFiles(); + $dir = $fs->getDir($this->project)->getPath(); + foreach($files as $file) { + $this->analyze($dir.DIRECTORY_SEPARATOR.$file); + } + } + } + $this->log("Number of findings: ".$this->counter, PROJECT_MSG_INFO); + } + + /** + * Analyze file + * + * @param string $file + * @return void + */ + protected function analyze($file) { + if(file_exists($file)) { + if(is_readable($file)) { + + // Construct shell command + $cmd = $this->analyzerPath." "; + foreach($this->enable as $enable) { // Enable warning levels + $cmd .= " --enable $enable "; + } + foreach($this->disable as $disable) { // Disable warning levels + $cmd .= " --disable $disable "; + } + $cmd .= "$file 2>&1"; + + // Execute command + $result = shell_exec($cmd); + $result = explode("\n", $result); + for($i=2, $size=count($result); $i<($size-1); $i++) { + $this->counter++; + $this->log($result[$i], PROJECT_MSG_WARN); + } + } else { + throw new BuildException('Permission denied: '.$file); + } + } else { + throw new BuildException('File not found: '.$file); + } + } +} + +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/ZipTask.php b/buildscripts/phing/classes/phing/tasks/ext/ZipTask.php new file mode 100644 index 00000000..33ef16ae --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/ZipTask.php @@ -0,0 +1,176 @@ +. + */ + +require_once 'phing/tasks/system/MatchingTask.php'; +include_once 'phing/util/SourceFileScanner.php'; +include_once 'phing/mappers/MergeMapper.php'; +include_once 'phing/util/StringHelper.php'; +include_once 'phing/lib/Zip.php'; + +/** + * Creates a zip archive using PEAR Archive_Zip (which is presently unreleased + * and included with Phing). + * + * @author Michiel Rook + * @version $Revision: 1.2 $ + * @package phing.tasks.ext + * @since 2.1.0 + */ +class ZipTask extends MatchingTask { + + private $zipFile; + private $baseDir; + + private $filesets = array(); + private $fileSetFiles = array(); + + /** + * Add a new fileset. + * @return FileSet + */ + public function createFileSet() { + $this->fileset = new FileSet(); + $this->filesets[] = $this->fileset; + return $this->fileset; + } + + /** + * Set is the name/location of where to create the zip file. + * @param PhingFile $destFile The output of the zip + */ + public function setDestFile(PhingFile $destFile) { + $this->zipFile = $destFile; + } + + /** + * This is the base directory to look in for things to zip. + * @param PhingFile $baseDir + */ + public function setBasedir(PhingFile $baseDir) { + $this->baseDir = $baseDir; + } + + /** + * do the work + * @throws BuildException + */ + public function main() { + + if ($this->zipFile === null) { + throw new BuildException("zipfile attribute must be set!", $this->getLocation()); + } + + if ($this->zipFile->exists() && $this->zipFile->isDirectory()) { + throw new BuildException("zipfile is a directory!", $this->getLocation()); + } + + if ($this->zipFile->exists() && !$this->zipFile->canWrite()) { + throw new BuildException("Can not write to the specified zipfile!", $this->getLocation()); + } + + // shouldn't need to clone, since the entries in filesets + // themselves won't be modified -- only elements will be added + $savedFileSets = $this->filesets; + + try { + if ($this->baseDir !== null) { + if (!$this->baseDir->exists()) { + throw new BuildException("basedir does not exist!", $this->getLocation()); + } + + // add the main fileset to the list of filesets to process. + $mainFileSet = new FileSet($this->fileset); + $mainFileSet->setDir($this->baseDir); + $this->filesets[] = $mainFileSet; + } + + if (empty($this->filesets)) { + throw new BuildException("You must supply either a basedir " + . "attribute or some nested filesets.", + $this->getLocation()); + } + + // check if zip is out of date with respect to each + // fileset + $upToDate = true; + foreach($this->filesets as $fs) { + $ds = $fs->getDirectoryScanner($this->project); + $files = $ds->getIncludedFiles(); + if (!$this->archiveIsUpToDate($files, $fs->getDir($this->project))) { + $upToDate = false; + } + for ($i=0, $fcount=count($files); $i < $fcount; $i++) { + if ($this->zipFile->equals(new PhingFile($fs->getDir($this->project), $files[$i]))) { + throw new BuildException("A zip file cannot include itself", $this->getLocation()); + } + } + } + + if ($upToDate) { + $this->log("Nothing to do: " . $this->zipFile->__toString() . " is up to date.", PROJECT_MSG_INFO); + return; + } + + $this->log("Building zip: " . $this->zipFile->__toString(), PROJECT_MSG_INFO); + + $zip = new Archive_Zip($this->zipFile->getAbsolutePath()); + + foreach($this->filesets as $fs) { + $ds = $fs->getDirectoryScanner($this->project); + $files = $ds->getIncludedFiles(); + + // FIXME + // Current model is only adding directories implicitly. This + // won't add any empty directories. Perhaps modify FileSet::getFiles() + // to also include empty directories. Not high priority, since non-inclusion + // of empty dirs is probably not unexpected behavior for ZipTask. + $fsBasedir = $fs->getDir($this->project); + $filesToZip = array(); + for ($i=0, $fcount=count($files); $i < $fcount; $i++) { + $f = new PhingFile($fsBasedir, $files[$i]); + $filesToZip[] = $f->getAbsolutePath(); + } + $zip->add($filesToZip, array('remove_path' => $fsBasedir->getPath())); + } + + + } catch (IOException $ioe) { + $msg = "Problem creating ZIP: " . $ioe->getMessage(); + $this->filesets = $savedFileSets; + throw new BuildException($msg, $ioe, $this->getLocation()); + } + + $this->filesets = $savedFileSets; + } + + /** + * @param array $files array of filenames + * @param PhingFile $dir + * @return boolean + */ + protected function archiveIsUpToDate($files, $dir) { + $sfs = new SourceFileScanner($this); + $mm = new MergeMapper(); + $mm->setTo($this->zipFile->getAbsolutePath()); + return count($sfs->restrict($files, $dir, null, $mm)) == 0; + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMerger.php b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMerger.php new file mode 100644 index 00000000..99bcc7c4 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMerger.php @@ -0,0 +1,127 @@ +. + */ + +require_once 'phing/system/util/Properties.php'; + +/** + * Saves coverage output of the test to a specified database + * + * @author Michiel Rook + * @version $Id: CoverageMerger.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.coverage + * @since 2.1.0 + */ +class CoverageMerger +{ + private static function mergeCodeCoverage($left, $right) + { + $coverageMerged = array(); + + reset($left); + reset($right); + + while (current($left) && current($right)) + { + $linenr_left = key($left); + $linenr_right = key($right); + + if ($linenr_left < $linenr_right) + { + $coverageMerged[$linenr_left] = current($left); + + next($left); + } + else + if ($linenr_right < $linenr_left) + { + $coverageMerged[$linenr_right] = current($right); + next($right); + } + else + { + if (current($left) < 0) + { + $coverageMerged[$linenr_right] = current($right); + } + else + if (current($right) < 0) + { + $coverageMerged[$linenr_right] = current($left); + } + else + { + $coverageMerged[$linenr_right] = current($left) + current($right); + } + + next($left); + next($right); + } + } + + while (current($left)) + { + $coverageMerged[key($left)] = current($left); + next($left); + } + + while (current($right)) + { + $coverageMerged[key($right)] = current($right); + next($right); + } + + return $coverageMerged; + } + + static function merge($project, $codeCoverageInformation) + { + $database = new PhingFile($project->getProperty('coverage.database')); + + $props = new Properties(); + $props->load($database); + + $coverageTotal = $codeCoverageInformation; + + foreach ($coverageTotal as $coverage) + { + foreach ($coverage as $filename => $coverageFile) + { + $filename = strtolower($filename); + + if ($props->getProperty($filename) != null) + { + $file = unserialize($props->getProperty($filename)); + $left = $file['coverage']; + $right = $coverageFile; + + $coverageMerged = CoverageMerger::mergeCodeCoverage($left, $right); + + $file['coverage'] = $coverageMerged; + + $props->setProperty($filename, serialize($file)); + } + } + } + + $props->store($database); + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMergerTask.php b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMergerTask.php new file mode 100644 index 00000000..4a78df6f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMergerTask.php @@ -0,0 +1,92 @@ +. + */ + +require_once 'phing/Task.php'; +require_once 'phing/system/io/PhingFile.php'; +require_once 'phing/system/io/Writer.php'; +require_once 'phing/system/util/Properties.php'; +require_once 'phing/tasks/ext/coverage/CoverageMerger.php'; + +/** + * Merges code coverage snippets into a code coverage database + * + * @author Michiel Rook + * @version $Id: CoverageMergerTask.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.coverage + * @since 2.1.0 + */ +class CoverageMergerTask extends Task +{ + /** the list of filesets containing the .php filename rules */ + private $filesets = array(); + + /** + * Add a new fileset containing the .php files to process + * + * @param FileSet the new fileset containing .php files + */ + function addFileSet(FileSet $fileset) + { + $this->filesets[] = $fileset; + } + + /** + * Iterate over all filesets and return all the filenames. + * + * @return array an array of filenames + */ + private function getFilenames() + { + $files = array(); + + foreach ($this->filesets as $fileset) + { + $ds = $fileset->getDirectoryScanner($this->project); + $ds->scan(); + + $includedFiles = $ds->getIncludedFiles(); + + foreach ($includedFiles as $file) + { + $fs = new PhingFile(basename($ds->getBaseDir()), $file); + + $files[] = $fs->getAbsolutePath(); + } + } + + return $files; + } + + function main() + { + $files = $this->getFilenames(); + + $this->log("Merging " . count($files) . " coverage files"); + + foreach ($files as $file) + { + $coverageInformation = unserialize(file_get_contents($file)); + + CoverageMerger::merge($this->project, array($coverageInformation)); + } + } +} +?> diff --git a/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTask.php b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTask.php new file mode 100644 index 00000000..72fa57a7 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTask.php @@ -0,0 +1,406 @@ +. + */ + +require_once 'phing/Task.php'; +require_once 'phing/system/io/PhingFile.php'; +require_once 'phing/system/io/Writer.php'; +require_once 'phing/system/util/Properties.php'; +require_once 'phing/tasks/ext/phpunit2/PHPUnit2Util.php'; +require_once 'phing/tasks/ext/coverage/CoverageReportTransformer.php'; + +/** + * Transforms information in a code coverage database to XML + * + * @author Michiel Rook + * @version $Id: CoverageReportTask.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.coverage + * @since 2.1.0 + */ +class CoverageReportTask extends Task +{ + private $outfile = "coverage.xml"; + + private $transformers = array(); + + /** the classpath to use (optional) */ + private $classpath = NULL; + + /** the path to the GeSHi library (optional) */ + private $geshipath = ""; + + /** the path to the GeSHi language files (optional) */ + private $geshilanguagespath = ""; + + function setClasspath(Path $classpath) + { + if ($this->classpath === null) + { + $this->classpath = $classpath; + } + else + { + $this->classpath->append($classpath); + } + } + + function createClasspath() + { + $this->classpath = new Path(); + return $this->classpath; + } + + function setGeshiPath($path) + { + $this->geshipath = $path; + } + + function setGeshiLanguagesPath($path) + { + $this->geshilanguagespath = $path; + } + + function __construct() + { + $this->doc = new DOMDocument(); + $this->doc->encoding = 'UTF-8'; + $this->doc->formatOutput = true; + $this->doc->appendChild($this->doc->createElement('snapshot')); + } + + function setOutfile($outfile) + { + $this->outfile = $outfile; + } + + /** + * Generate a report based on the XML created by this task + */ + function createReport() + { + $transformer = new CoverageReportTransformer($this); + $this->transformers[] = $transformer; + return $transformer; + } + + protected function getPackageElement($packageName) + { + $packages = $this->doc->documentElement->getElementsByTagName('package'); + + foreach ($packages as $package) + { + if ($package->getAttribute('name') == $packageName) + { + return $package; + } + } + + return NULL; + } + + protected function addClassToPackage($classname, $element) + { + $packageName = PHPUnit2Util::getPackageName($classname); + + $package = $this->getPackageElement($packageName); + + if ($package === NULL) + { + $package = $this->doc->createElement('package'); + $package->setAttribute('name', $packageName); + $this->doc->documentElement->appendChild($package); + } + + $package->appendChild($element); + } + + protected function stripDiv($source) + { + $openpos = strpos($source, "", $openpos); + + $line = substr($source, $closepos + 1); + + $tagclosepos = strpos($line, "
        "); + + $line = substr($line, 0, $tagclosepos); + + return $line; + } + + protected function highlightSourceFile($filename) + { + if ($this->geshipath) + { + require_once $this->geshipath . '/geshi.php'; + + $source = file_get_contents($filename); + + $geshi = new GeSHi($source, 'php', $this->geshilanguagespath); + + $geshi->enable_line_numbers(GESHI_NORMAL_LINE_NUMBERS); + + $geshi->enable_strict_mode(true); + + $geshi->enable_classes(true); + + $geshi->set_url_for_keyword_group(3, ''); + + $html = $geshi->parse_code(); + + $lines = split("
      • |
      • ", $html); + + // skip first and last line + array_pop($lines); + array_shift($lines); + + $lines = array_filter($lines); + + $lines = array_map(array($this, 'stripDiv'), $lines); + + return $lines; + } + else + { + $lines = file($filename); + + for ($i = 0; $i < count($lines); $i++) + { + $line = $lines[$i]; + + $line = rtrim($line); + + $lines[$i] = utf8_encode($line); + } + + return $lines; + } + } + + protected function transformSourceFile($filename, $coverageInformation, $classStartLine = 1) + { + $sourceElement = $this->doc->createElement('sourcefile'); + $sourceElement->setAttribute('name', basename($filename)); + + $filelines = $this->highlightSourceFile($filename); + + $linenr = 1; + + foreach ($filelines as $line) + { + $lineElement = $this->doc->createElement('sourceline'); + $lineElement->setAttribute('coveredcount', (isset($coverageInformation[$linenr]) ? $coverageInformation[$linenr] : '0')); + + if ($linenr == $classStartLine) + { + $lineElement->setAttribute('startclass', 1); + } + + $textnode = $this->doc->createTextNode($line); + $lineElement->appendChild($textnode); + + $sourceElement->appendChild($lineElement); + + $linenr++; + } + + return $sourceElement; + } + + protected function filterCovered($var) + { + return ($var >= 0); + } + + protected function transformCoverageInformation($filename, $coverageInformation) + { + $classes = PHPUnit2Util::getDefinedClasses($filename, $this->classpath); + + if (is_array($classes)) + { + foreach ($classes as $classname) + { + $reflection = new ReflectionClass($classname); + + $methods = $reflection->getMethods(); + + $classElement = $this->doc->createElement('class'); + $classElement->setAttribute('name', $reflection->getName()); + + $this->addClassToPackage($reflection->getName(), $classElement); + + $classStartLine = $reflection->getStartLine(); + + $methodscovered = 0; + $methodcount = 0; + + end($coverageInformation); + unset($coverageInformation[key($coverageInformation)]); + + // Strange PHP5 reflection bug, classes without parent class or implemented interfaces seem to start one line off + if ($reflection->getParentClass() == NULL && count($reflection->getInterfaces()) == 0) + { + unset($coverageInformation[$classStartLine + 1]); + } + else + { + unset($coverageInformation[$classStartLine]); + } + + reset($coverageInformation); + + foreach ($methods as $method) + { + // PHP5 reflection considers methods of a parent class to be part of a subclass, we don't + if ($method->getDeclaringClass()->getName() != $reflection->getName()) + { + continue; + } + + // small fix for XDEBUG_CC_UNUSED + if (isset($coverageInformation[$method->getStartLine()])) + { + unset($coverageInformation[$method->getStartLine()]); + } + + if (isset($coverageInformation[$method->getEndLine()])) + { + unset($coverageInformation[$method->getEndLine()]); + } + + if ($method->isAbstract()) + { + continue; + } + + $linenr = key($coverageInformation); + + while ($linenr < $method->getStartLine()) + { + next($coverageInformation); + $linenr = key($coverageInformation); + } + + if (current($coverageInformation) > 0 && $method->getStartLine() <= $linenr && $linenr <= $method->getEndLine()) + { + $methodscovered++; + } + + $methodcount++; + } + + $statementcount = count($coverageInformation); + $statementscovered = count(array_filter($coverageInformation, array($this, 'filterCovered'))); + + $classElement->appendChild($this->transformSourceFile($filename, $coverageInformation, $classStartLine)); + + $classElement->setAttribute('methodcount', $methodcount); + $classElement->setAttribute('methodscovered', $methodscovered); + $classElement->setAttribute('statementcount', $statementcount); + $classElement->setAttribute('statementscovered', $statementscovered); + $classElement->setAttribute('totalcount', $methodcount + $statementcount); + $classElement->setAttribute('totalcovered', $methodscovered + $statementscovered); + } + } + } + + protected function calculateStatistics() + { + $packages = $this->doc->documentElement->getElementsByTagName('package'); + + $totalmethodcount = 0; + $totalmethodscovered = 0; + + $totalstatementcount = 0; + $totalstatementscovered = 0; + + foreach ($packages as $package) + { + $methodcount = 0; + $methodscovered = 0; + + $statementcount = 0; + $statementscovered = 0; + + $classes = $package->getElementsByTagName('class'); + + foreach ($classes as $class) + { + $methodcount += $class->getAttribute('methodcount'); + $methodscovered += $class->getAttribute('methodscovered'); + + $statementcount += $class->getAttribute('statementcount'); + $statementscovered += $class->getAttribute('statementscovered'); + } + + $package->setAttribute('methodcount', $methodcount); + $package->setAttribute('methodscovered', $methodscovered); + + $package->setAttribute('statementcount', $statementcount); + $package->setAttribute('statementscovered', $statementscovered); + + $package->setAttribute('totalcount', $methodcount + $statementcount); + $package->setAttribute('totalcovered', $methodscovered + $statementscovered); + + $totalmethodcount += $methodcount; + $totalmethodscovered += $methodscovered; + + $totalstatementcount += $statementcount; + $totalstatementscovered += $statementscovered; + } + + $this->doc->documentElement->setAttribute('methodcount', $totalmethodcount); + $this->doc->documentElement->setAttribute('methodscovered', $totalmethodscovered); + + $this->doc->documentElement->setAttribute('statementcount', $totalstatementcount); + $this->doc->documentElement->setAttribute('statementscovered', $totalstatementscovered); + + $this->doc->documentElement->setAttribute('totalcount', $totalmethodcount + $totalstatementcount); + $this->doc->documentElement->setAttribute('totalcovered', $totalmethodscovered + $totalstatementscovered); + } + + function main() + { + $this->log("Transforming coverage report"); + + $database = new PhingFile($this->project->getProperty('coverage.database')); + + $props = new Properties(); + $props->load($database); + + foreach ($props->keys() as $filename) + { + $file = unserialize($props->getProperty($filename)); + + $this->transformCoverageInformation($file['fullname'], $file['coverage']); + } + + $this->calculateStatistics(); + + $this->doc->save($this->outfile); + + foreach ($this->transformers as $transformer) + { + $transformer->setXmlDocument($this->doc); + $transformer->transform(); + } + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTransformer.php b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTransformer.php new file mode 100644 index 00000000..b7fee32f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTransformer.php @@ -0,0 +1,121 @@ +. + */ + +require_once 'phing/Task.php'; +require_once 'phing/system/io/PhingFile.php'; +require_once 'phing/system/io/FileWriter.php'; +require_once 'phing/util/ExtendedFileStream.php'; + +/** + * Transform a Phing/Xdebug code coverage xml report. + * The default transformation generates an html report in framed style. + * + * @author Michiel Rook + * @version $Id: CoverageReportTransformer.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.coverage + * @since 2.1.0 + */ +class CoverageReportTransformer +{ + private $task = NULL; + private $styleDir = ""; + private $toDir = ""; + private $document = NULL; + + function __construct(Task $task) + { + $this->task = $task; + } + + function setStyleDir($styleDir) + { + $this->styleDir = $styleDir; + } + + function setToDir($toDir) + { + $this->toDir = $toDir; + } + + function setXmlDocument($document) + { + $this->document = $document; + } + + function transform() + { + $dir = new PhingFile($this->toDir); + + if (!$dir->exists()) + { + throw new BuildException("Directory '" . $this->toDir . "' does not exist"); + } + + $xslfile = $this->getStyleSheet(); + + $xsl = new DOMDocument(); + $xsl->load($xslfile->getAbsolutePath()); + + $proc = new XSLTProcessor(); + $proc->importStyleSheet($xsl); + + ExtendedFileStream::registerStream(); + + // no output for the framed report + // it's all done by extension... + $proc->setParameter('', 'output.dir', $dir->getAbsolutePath()); + $proc->transformToXML($this->document); + } + + private function getStyleSheet() + { + $xslname = "coverage-frames.xsl"; + + if ($this->styleDir) + { + $file = new PhingFile($this->styleDir, $xslname); + } + else + { + $path = Phing::getResourcePath("phing/etc/$xslname"); + + if ($path === NULL) + { + $path = Phing::getResourcePath("etc/$xslname"); + + if ($path === NULL) + { + throw new BuildException("Could not find $xslname in resource path"); + } + } + + $file = new PhingFile($path); + } + + if (!$file->exists()) + { + throw new BuildException("Could not find file " . $file->getPath()); + } + + return $file; + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageSetupTask.php b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageSetupTask.php new file mode 100644 index 00000000..058b891b --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageSetupTask.php @@ -0,0 +1,163 @@ +. + */ + +require_once 'phing/Task.php'; +require_once 'phing/system/io/PhingFile.php'; +require_once 'phing/system/io/Writer.php'; +require_once 'phing/system/util/Properties.php'; +require_once 'phing/tasks/ext/coverage/CoverageMerger.php'; + +/** + * Initializes a code coverage database + * + * @author Michiel Rook + * @version $Id: CoverageSetupTask.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.coverage + * @since 2.1.0 + */ +class CoverageSetupTask extends Task +{ + /** the list of filesets containing the .php filename rules */ + private $filesets = array(); + + /** the filename of the coverage database */ + private $database = "coverage.db"; + + /** the classpath to use (optional) */ + private $classpath = NULL; + + /** + * Add a new fileset containing the .php files to process + * + * @param FileSet the new fileset containing .php files + */ + function addFileSet(FileSet $fileset) + { + $this->filesets[] = $fileset; + } + + /** + * Sets the filename of the coverage database to use + * + * @param string the filename of the database + */ + function setDatabase($database) + { + $this->database = $database; + } + + function setClasspath(Path $classpath) + { + if ($this->classpath === null) + { + $this->classpath = $classpath; + } + else + { + $this->classpath->append($classpath); + } + } + + function createClasspath() + { + $this->classpath = new Path(); + return $this->classpath; + } + + /** + * Iterate over all filesets and return the filename of all files + * that end with .php. This is to avoid loading an xml file + * for example. + * + * @return array an array of (basedir, filenames) pairs + */ + private function getFilenames() + { + $files = array(); + + foreach ($this->filesets as $fileset) + { + $ds = $fileset->getDirectoryScanner($this->project); + $ds->scan(); + + $includedFiles = $ds->getIncludedFiles(); + + foreach ($includedFiles as $file) + { + if (strstr($file, ".php")) + { + $fs = new PhingFile(realpath($ds->getBaseDir()), $file); + + $files[] = array('key' => strtolower($fs->getAbsolutePath()), 'fullname' => $fs->getAbsolutePath()); + } + } + } + + return $files; + } + + function init() + { + include_once 'PHPUnit2/Framework/TestCase.php'; + if (!class_exists('PHPUnit2_Framework_TestCase')) { + throw new Exception("PHPUnit2Task depends on PEAR PHPUnit2 package being installed."); + } + } + + function main() + { + $files = $this->getFilenames(); + + $this->log("Setting up coverage database for " . count($files) . " files"); + + $props = new Properties(); + + foreach ($files as $file) + { + $fullname = $file['fullname']; + $filename = $file['key']; + + $props->setProperty($filename, serialize(array('fullname' => $fullname, 'coverage' => array()))); + } + + $dbfile = new PhingFile($this->database); + + $props->store($dbfile); + + $this->project->setProperty('coverage.database', $dbfile->getAbsolutePath()); + + foreach ($files as $file) + { + $fullname = $file['fullname']; + + xdebug_start_code_coverage(XDEBUG_CC_UNUSED); + + Phing::__import($fullname, $this->classpath); + + $coverage = xdebug_get_code_coverage(); + + xdebug_stop_code_coverage(); + + CoverageMerger::merge($this->project, array($coverage)); + } + } +} +?> diff --git a/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeComment.php b/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeComment.php new file mode 100644 index 00000000..99434aaa --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeComment.php @@ -0,0 +1,44 @@ +. + */ + +/** + * Wrapper for comments for ionCube tasks + * + * @author Michiel Rook + * @version $Id: IoncubeComment.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.ioncube + * @since 2.2.0 + */ +class IoncubeComment +{ + private $value = ""; + + public function getValue() + { + return $this->value; + } + + public function addText($txt) + { + $this->value = trim($txt); + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeEncoderTask.php b/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeEncoderTask.php new file mode 100644 index 00000000..9eecd5a0 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeEncoderTask.php @@ -0,0 +1,336 @@ +. + */ + +require_once 'phing/Task.php'; +require_once 'phing/tasks/ext/ioncube/IoncubeComment.php'; + +/** + * Invokes the ionCube Encoder (PHP4 or PHP5) + * + * @author Michiel Rook + * @version $Id: IoncubeEncoderTask.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.ioncube + * @since 2.2.0 + */ +class IoncubeEncoderTask extends Task +{ + private $phpVersion = "5"; + private $ioncubePath = "/usr/local/ioncube"; + private $encoderName = "ioncube_encoder"; + + private $fromDir = ""; + private $toDir = ""; + + private $encrypt = ""; + + private $targetOption = ""; + private $binary = false; + private $optimize = ""; + private $withoutRuntimeLoaderSupport = false; + + private $licensePath = ""; + private $passPhrase = ""; + + private $comments = array(); + + /** + * Sets the path to the ionCube encoder + */ + function setIoncubePath($ioncubePath) + { + $this->ioncubePath = $ioncubePath; + } + + /** + * Returns the path to the ionCube encoder + */ + function getIoncubePath() + { + return $this->ioncubePath; + } + + /** + * Sets the version of PHP to use (defaults to 5) + */ + function setPhpVersion($phpVersion) + { + $this->phpVersion = $phpVersion; + } + + /** + * Returns the version of PHP to use (defaults to 5) + */ + function getPhpVersion() + { + return $this->phpVersion; + } + + /** + * Sets the source directory + */ + function setFromDir($fromDir) + { + $this->fromDir = $fromDir; + } + + /** + * Returns the source directory + */ + function getFromDir($fromDir) + { + return $this->fromDir; + } + + /** + * Sets the target directory + */ + function setToDir($toDir) + { + $this->toDir = $toDir; + } + + /** + * Returns the target directory + */ + function getToDir($toDir) + { + return $this->toDir; + } + + /** + * Sets regexps of additional files to encrypt (separated by space) + */ + function setEncrypt($encrypt) + { + $this->encrypt = $encrypt; + } + + /** + * Returns regexps of additional files to encrypt (separated by space) + */ + function getEncrypt() + { + return $this->encrypt; + } + + /** + * Sets the binary option + */ + function setBinary($binary) + { + $this->binary = $binary; + } + + /** + * Returns the binary option + */ + function getBinary() + { + return $this->binary; + } + + /** + * Sets the optimize option + */ + function setOptimize($optimize) + { + $this->optimize = $optimize; + } + + /** + * Returns the optimize option + */ + function getOptimize() + { + return $this->optimize; + } + + /** + * Sets the without-runtime-loader-support option + */ + function setWithoutRuntimeLoaderSupport($withoutRuntimeLoaderSupport) + { + $this->withoutRuntimeLoaderSupport = $withoutRuntimeLoaderSupport; + } + + /** + * Returns the without-runtime-loader-support option + */ + function getWithoutRuntimeLoaderSupport() + { + return $this->withoutRuntimeLoaderSupport; + } + + /** + * Sets the option to use when encoding target directory already exists (defaults to none) + */ + function setTargetOption($targetOption) + { + $this->targetOption = $targetOption; + } + + /** + * Returns he option to use when encoding target directory already exists (defaults to none) + */ + function getTargetOption() + { + return $this->targetOption; + } + + /** + * Sets the path to the license file to use + */ + function setLicensePath($licensePath) + { + $this->licensePath = $licensePath; + } + + /** + * Returns the path to the license file to use + */ + function getLicensePath() + { + return $this->licensePath; + } + + /** + * Sets the passphrase to use when encoding files + */ + function setPassPhrase($passPhrase) + { + $this->passPhrase = $passPhrase; + } + + /** + * Returns the passphrase to use when encoding files + */ + function getPassPhrase() + { + return $this->passPhrase; + } + + /** + * Adds a comment to be used in encoded files + */ + function addComment(IoncubeComment $comment) + { + $this->comments[] = $comment; + } + + /** + * The main entry point + * + * @throws BuildException + */ + function main() + { + $arguments = $this->constructArguments(); + + $encoder = new PhingFile($this->ioncubePath, $this->encoderName . ($this->phpVersion == 5 ? '5' : '')); + + $this->log("Running ionCube Encoder..."); + + exec($encoder->__toString() . " " . $arguments . " 2>&1", $output, $return); + + if ($return != 0) + { + throw new BuildException("Could not execute ionCube Encoder: " . implode(' ', $output)); + } + } + + /** + * Constructs an argument string for the ionCube encoder + */ + private function constructArguments() + { + $arguments = ""; + + if ($this->binary) + { + $arguments.= "--binary "; + } + + if (!empty($this->optimize)) + { + $arguments.= "--optimize " . $this->optimize . " "; + } + + if ($this->withoutRuntimeLoaderSupport) + { + $arguments.= "--without-runtime-loader-support "; + } + + if (!empty($this->targetOption)) + { + switch ($this->targetOption) + { + case "replace": + case "merge": + case "update": + case "rename": + { + $arguments.= "--" . $this->targetOption . "-target "; + } break; + + default: + { + throw new BuildException("Unknown target option '" . $this->targetOption . "'"); + } break; + } + } + + if (!empty($this->encrypt)) + { + foreach (explode(" ", $this->encrypt) as $encrypt) + { + $arguments.= "--encrypt '$encrypt' "; + } + } + + if (!empty($this->licensePath)) + { + $arguments.= "--with-license '" . $this->licensePath . "' "; + } + + if (!empty($this->passPhrase)) + { + $arguments.= "--passphrase '" . $this->passPhrase . "' "; + } + + foreach ($this->comments as $comment) + { + $arguments.= "--add-comment '" . $comment->getValue() . "' "; + } + + if ($this->fromDir != "") + { + $arguments .= $this->fromDir . " "; + } + + if ($this->toDir != "") + { + $arguments .= "-o " . $this->toDir . " "; + } + + return $arguments; + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeLicenseTask.php b/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeLicenseTask.php new file mode 100644 index 00000000..70abd544 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeLicenseTask.php @@ -0,0 +1,144 @@ +. + */ + +require_once 'phing/Task.php'; +require_once 'phing/tasks/ext/ioncube/IoncubeComment.php'; + +/** + * Invokes the ionCube "make_license" program + * + * @author Michiel Rook + * @version $Id: IoncubeLicenseTask.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.ioncube + * @since 2.2.0 + */ +class IoncubeLicenseTask extends Task +{ + private $ioncubePath = "/usr/local/ioncube"; + + private $licensePath = ""; + private $passPhrase = ""; + + private $comments = array(); + + /** + * Sets the path to the ionCube encoder + */ + function setIoncubePath($ioncubePath) + { + $this->ioncubePath = $ioncubePath; + } + + /** + * Returns the path to the ionCube encoder + */ + function getIoncubePath() + { + return $this->ioncubePath; + } + + /** + * Sets the path to the license file to use + */ + function setLicensePath($licensePath) + { + $this->licensePath = $licensePath; + } + + /** + * Returns the path to the license file to use + */ + function getLicensePath() + { + return $this->licensePath; + } + + /** + * Sets the passphrase to use when encoding files + */ + function setPassPhrase($passPhrase) + { + $this->passPhrase = $passPhrase; + } + + /** + * Returns the passphrase to use when encoding files + */ + function getPassPhrase() + { + return $this->passPhrase; + } + + /** + * Adds a comment to be used in encoded files + */ + function addComment(IoncubeComment $comment) + { + $this->comments[] = $comment; + } + + /** + * The main entry point + * + * @throws BuildException + */ + function main() + { + $arguments = $this->constructArguments(); + + $makelicense = new PhingFile($this->ioncubePath, 'make_license'); + + $this->log("Running ionCube make_license..."); + + exec($makelicense->__toString() . " " . $arguments . " 2>&1", $output, $return); + + if ($return != 0) + { + throw new BuildException("Could not execute ionCube make_license: " . implode(' ', $output)); + } + } + + /** + * Constructs an argument string for the ionCube make_license + */ + private function constructArguments() + { + $arguments = ""; + + if (!empty($this->passPhrase)) + { + $arguments.= "--passphrase '" . $this->passPhrase . "' "; + } + + foreach ($this->comments as $comment) + { + $arguments.= "--header-line '" . $comment->getValue() . "' "; + } + + if (!empty($this->licensePath)) + { + $arguments.= "--o '" . $this->licensePath . "' "; + } + + return $arguments; + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/pearpackage/Fileset.php b/buildscripts/phing/classes/phing/tasks/ext/pearpackage/Fileset.php new file mode 100644 index 00000000..12bd4e55 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/pearpackage/Fileset.php @@ -0,0 +1,231 @@ +. + */ + +include_once 'phing/system/io/PhingFile.php'; + +/** + * Builds list of files for PEAR_PackageFileManager using a Phing FileSet. + * + * Some code here is taken from PEAR_PackageFileManager_File -- getting results from flat + * array into the assoc array expected from getFileList(). + * + * @author Greg Beaver + * @author Hans Lellelid + * @package phing.tasks.ext.pearpackage + * @version $Revision: 1.7 $ + */ +class PEAR_PackageFileManager_Fileset { + + /** + * @access private + * @var PEAR_PackageFileManager + */ + private $parent; + + /** + * Curent Phing Project. + * @var Project + */ + private $project; + + /** + * FileSets to use. + * @var array FileSet[] + */ + private $filesets = array(); + + /** + * Set up the FileSet filelist generator + * + * 'project' and 'filesets' are the only options that this class uses. + * + * @param PEAR_PackageFileManager + * @param array + */ + function __construct($parent, $options) + { + $this->parent = $parent; + $this->project = $options['phing_project']; + $this->filesets = $options['phing_filesets']; + } + + /** + * Generate the section + * of the package file. + * + * This function performs the backend generation of the array + * containing all files in this package + * @return array structure of all files to include + */ + function getFileList() { + + $allfiles = array(); + + foreach($this->filesets as $fs) { + $ds = $fs->getDirectoryScanner($this->project); + + $files = $ds->getIncludedFiles(); + + // We need to store these files keyed by the basedir from DirectoryScanner + // so that we can resolve the fullpath of the file later. + if (isset($allfiles[$ds->getBasedir()])) + { + $allfiles[$ds->getBasedir()] = array_merge($allfiles[$ds->getBasedir()], $files); + } + else + { + $allfiles[$ds->getBasedir()] = $files; + } + } + + $struc = array(); + + foreach($allfiles as $basedir => $files) { + + foreach($files as $file) { + + // paths are relative to $basedir above + $path = strtr(dirname($file), DIRECTORY_SEPARATOR, '/'); + + if (!$path || $path == '.') { + $path = '/'; // for array index + } + + $parts = explode('.', basename($file)); + $ext = array_pop($parts); + if (strlen($ext) == strlen($file)) { + $ext = ''; + } + + $f = new PhingFile($basedir, $file); + + $struc[$path][] = array('file' => basename($file), + 'ext' => $ext, + 'path' => (($path == '/') ? basename($file) : $path . '/' . basename($file)), + 'fullpath' => $f->getAbsolutePath()); + } + } + + uksort($struc,'strnatcasecmp'); + foreach($struc as $key => $ind) { + usort($ind, array($this, 'sortfiles')); + $struc[$key] = $ind; + } + + $tempstruc = $struc; + $struc = array('/' => $tempstruc['/']); + $bv = 0; + foreach($tempstruc as $key => $ind) { + $save = $key; + if ($key != '/') { + $struc['/'] = $this->setupDirs($struc['/'], explode('/', $key), $tempstruc[$key]); + } + } + uksort($struc['/'], array($this, 'mystrucsort')); + + return $struc; + } + + /** + * Recursively move contents of $struc into associative array + * + * The contents of $struc have many indexes like 'dir/subdir/subdir2'. + * This function converts them to + * array('dir' => array('subdir' => array('subdir2'))) + * @param array struc is array('dir' => array of files in dir, + * 'dir/subdir' => array of files in dir/subdir,...) + * @param array array form of 'dir/subdir/subdir2' array('dir','subdir','subdir2') + * @return array same as struc but with array('dir' => + * array(file1,file2,'subdir' => array(file1,...))) + */ + private function setupDirs($struc, $dir, $contents) { + + if (!count($dir)) { + foreach($contents as $dir => $files) { + if (is_string($dir)) { + if (strpos($dir, '/')) { + $test = true; + $a = $contents[$dir]; + unset($contents[$dir]); + $b = explode('/', $dir); + $c = array_shift($b); + if (isset($contents[$c])) { + $contents[$c] = $this->setDir($contents[$c], $this->setupDirs(array(), $b, $a)); + } else { + $contents[$c] = $this->setupDirs(array(), $b, $a); + } + } + } + } + return $contents; + } + $me = array_shift($dir); + if (!isset($struc[$me])) { + $struc[$me] = array(); + } + $struc[$me] = $this->setupDirs($struc[$me], $dir, $contents); + return $struc; + } + + /** + * Recursively add all the subdirectories of $contents to $dir without erasing anything in + * $dir + * @param array + * @param array + * @return array processed $dir + */ + function setDir($dir, $contents) + { + while(list($one,$two) = each($contents)) { + if (isset($dir[$one])) { + $dir[$one] = $this->setDir($dir[$one], $contents[$one]); + } else { + $dir[$one] = $two; + } + } + return $dir; + } + + /** + * Sorting functions for the file list + * @param string + * @param string + * @access private + */ + function sortfiles($a, $b) + { + return strnatcasecmp($a['file'],$b['file']); + } + + function mystrucsort($a, $b) + { + if (is_numeric($a) && is_string($b)) return 1; + if (is_numeric($b) && is_string($a)) return -1; + if (is_numeric($a) && is_numeric($b)) + { + if ($a > $b) return 1; + if ($a < $b) return -1; + if ($a == $b) return 0; + } + return strnatcasecmp($a,$b); + } +} +?> diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PHPDocumentorTask.php b/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PHPDocumentorTask.php new file mode 100644 index 00000000..2fefc4e5 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PHPDocumentorTask.php @@ -0,0 +1,157 @@ +. + */ + + require_once 'phing/Task.php'; + + /** + * Task to run phpDocumentor. + * + * @author Michiel Rook + * @version $Id: PHPDocumentorTask.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpdoc + */ + class PHPDocumentorTask extends Task + { + /** + * The name of the executable for phpDocumentor + */ + const PHPDOC = 'phpdoc'; + + private $title = "Default Title"; + + private $destdir = "."; + + private $sourcepath = NULL; + + private $output = ""; + + private $linksource = false; + + private $parseprivate = false; + + /** + * Set the title for the generated documentation + */ + function setTitle($title) + { + $this->title = $title; + } + + /** + * Set the destination directory for the generated documentation + */ + function setDestdir($destdir) + { + $this->destdir = $destdir; + } + + /** + * Set the source path + */ + function setSourcepath(Path $sourcepath) + { + if ($this->sourcepath === NULL) + { + $this->sourcepath = $sourcepath; + } + else + { + $this->sourcepath->append($sourcepath); + } + } + + /** + * Set the output type + */ + function setOutput($output) + { + $this->output = $output; + } + + /** + * Should sources be linked in the generated documentation + */ + function setLinksource($linksource) + { + $this->linksource = $linksource; + } + + /** + * Should private members/classes be documented + */ + function setParseprivate($parseprivate) + { + $this->parseprivate = $parseprivate; + } + + /** + * Main entrypoint of the task + */ + function main() + { + $arguments = $this->constructArguments(); + + exec(self::PHPDOC . " " . $arguments, $output, $retval); + } + + /** + * Constructs an argument string for phpDocumentor + */ + private function constructArguments() + { + $arguments = "-q "; + + if ($this->title) + { + $arguments.= "-ti \"" . $this->title . "\" "; + } + + if ($this->destdir) + { + $arguments.= "-t " . $this->destdir . " "; + } + + if ($this->sourcepath !== NULL) + { + $arguments.= "-d " . $this->sourcepath->__toString() . " "; + } + + if ($this->output) + { + $arguments.= "-o " . $this->output . " "; + } + + if ($this->linksource) + { + $arguments.= "-s "; + } + + if ($this->parseprivate) + { + $arguments.= "-pp "; + } + + return $arguments; + } + }; + +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/BatchTest.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/BatchTest.php new file mode 100644 index 00000000..63f8911a --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/BatchTest.php @@ -0,0 +1,171 @@ +. + */ + +require_once 'phing/types/FileSet.php'; + +/** + * Scans a list of (.php) files given by the fileset attribute, extracts + * all subclasses of PHPUnit2_Framework_TestCase. + * + * @author Michiel Rook + * @version $Id: BatchTest.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +class BatchTest +{ + /** the list of filesets containing the testcase filename rules */ + private $filesets = array(); + + /** the reference to the project */ + private $project = NULL; + + /** the classpath to use with Phing::__import() calls */ + private $classpath = NULL; + + /** names of classes to exclude */ + private $excludeClasses = array(); + + /** + * Create a new batchtest instance + * + * @param Project the project it depends on. + */ + function __construct(Project $project) + { + $this->project = $project; + } + + /** + * Sets the classes to exclude + */ + function setExclude($exclude) + { + $this->excludeClasses = explode(" ", $exclude); + } + + /** + * Sets the classpath + */ + function setClasspath(Path $classpath) + { + if ($this->classpath === null) + { + $this->classpath = $classpath; + } + else + { + $this->classpath->append($classpath); + } + } + + /** + * Creates a new Path object + */ + function createClasspath() + { + $this->classpath = new Path(); + return $this->classpath; + } + + /** + * Returns the classpath + */ + function getClasspath() + { + return $this->classpath; + } + + /** + * Add a new fileset containing the XML results to aggregate + * + * @param FileSet the new fileset containing XML results. + */ + function addFileSet(FileSet $fileset) + { + $this->filesets[] = $fileset; + } + + /** + * Iterate over all filesets and return the filename of all files + * that end with .php. + * + * @return array an array of filenames + */ + private function getFilenames() + { + $filenames = array(); + + foreach ($this->filesets as $fileset) + { + $ds = $fileset->getDirectoryScanner($this->project); + $ds->scan(); + + $files = $ds->getIncludedFiles(); + + foreach ($files as $file) + { + if (strstr($file, ".php")) + { + $filenames[] = $ds->getBaseDir() . "/" . $file; + } + } + } + + return $filenames; + } + + /** + * Filters an array of classes, removes all classes that are not subclasses of PHPUnit2_Framework_TestCase, + * or classes that are declared abstract + */ + private function filterTests($input) + { + $reflect = new ReflectionClass($input); + + return is_subclass_of($input, 'PHPUnit2_Framework_TestCase') && (!$reflect->isAbstract()); + } + + /** + * Returns an array of PHPUnit2_Framework_TestCase classes that are declared + * by the files included by the filesets + * + * @return array an array of PHPUnit2_Framework_TestCase classes. + */ + function elements() + { + $filenames = $this->getFilenames(); + + $declaredClasses = array(); + + foreach ($filenames as $filename) + { + $definedClasses = PHPUnit2Util::getDefinedClasses($filename); + + $declaredClasses = array_merge($declaredClasses, $definedClasses); + } + + $elements = array_filter($declaredClasses, array($this, "filterTests")); + + return $elements; + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/FormatterElement.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/FormatterElement.php new file mode 100644 index 00000000..9d2a4656 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/FormatterElement.php @@ -0,0 +1,120 @@ +. + */ + +require_once 'phing/tasks/ext/phpunit2/XMLPHPUnit2ResultFormatter.php'; +require_once 'phing/tasks/ext/phpunit2/PlainPHPUnit2ResultFormatter.php'; +require_once 'phing/system/io/PhingFile.php'; + +/** + * A wrapper for the implementations of PHPUnit2ResultFormatter. + * + * @author Michiel Rook + * @version $Id: FormatterElement.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +class FormatterElement +{ + protected $formatter = NULL; + + protected $type = ""; + + protected $useFile = true; + + protected $toDir = "."; + + protected $outfile = ""; + + function setType($type) + { + $this->type = $type; + + if ($this->type == "xml") + { + $destFile = new PhingFile($this->toDir, 'testsuites.xml'); + $this->formatter = new XMLPHPUnit2ResultFormatter(); + } + else + if ($this->type == "plain") + { + $this->formatter = new PlainPHPUnit2ResultFormatter(); + } + else + { + throw new BuildException("Formatter '" . $this->type . "' not implemented"); + } + } + + function setClassName($className) + { + $classNameNoDot = Phing::import($className); + + $this->formatter = new $classNameNoDot(); + } + + function setUseFile($useFile) + { + $this->useFile = $useFile; + } + + function getUseFile() + { + return $this->useFile; + } + + function setToDir($toDir) + { + $this->toDir = $toDir; + } + + function getToDir() + { + return $this->toDir; + } + + function setOutfile($outfile) + { + $this->outfile = $outfile; + } + + function getOutfile() + { + if ($this->outfile) + { + return $this->outfile; + } + else + { + return $this->formatter->getPreferredOutfile() . $this->getExtension(); + } + } + + function getExtension() + { + return $this->formatter->getExtension(); + } + + function getFormatter() + { + return $this->formatter; + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2ReportTask.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2ReportTask.php new file mode 100644 index 00000000..1e08e79c --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2ReportTask.php @@ -0,0 +1,162 @@ +. + */ + +require_once 'phing/Task.php'; +require_once 'phing/system/io/PhingFile.php'; +require_once 'phing/system/io/FileWriter.php'; +require_once 'phing/util/ExtendedFileStream.php'; + +/** + * Transform a PHPUnit2 xml report using XSLT. + * This transformation generates an html report in either framed or non-framed + * style. The non-framed style is convenient to have a concise report via mail, + * the framed report is much more convenient if you want to browse into + * different packages or testcases since it is a Javadoc like report. + * + * @author Michiel Rook + * @version $Id: PHPUnit2ReportTask.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +class PHPUnit2ReportTask extends Task +{ + private $format = "noframes"; + private $styleDir = ""; + private $toDir = ""; + + /** the directory where the results XML can be found */ + private $inFile = "testsuites.xml"; + + /** + * Set the filename of the XML results file to use. + */ + function setInFile($inFile) + { + $this->inFile = $inFile; + } + + /** + * Set the format of the generated report. Must be noframes or frames. + */ + function setFormat($format) + { + $this->format = $format; + } + + /** + * Set the directory where the stylesheets are located. + */ + function setStyleDir($styleDir) + { + $this->styleDir = $styleDir; + } + + /** + * Set the directory where the files resulting from the + * transformation should be written to. + */ + function setToDir($toDir) + { + $this->toDir = $toDir; + } + + private function getStyleSheet() + { + $xslname = "phpunit2-" . $this->format . ".xsl"; + + if ($this->styleDir) + { + $file = new PhingFile($this->styleDir, $xslname); + } + else + { + $path = Phing::getResourcePath("phing/etc/$xslname"); + + if ($path === NULL) + { + $path = Phing::getResourcePath("etc/$xslname"); + + if ($path === NULL) + { + throw new BuildException("Could not find $xslname in resource path"); + } + } + + $file = new PhingFile($path); + } + + if (!$file->exists()) + { + throw new BuildException("Could not find file " . $file->getPath()); + } + + return $file; + } + + function transform($document) + { + $dir = new PhingFile($this->toDir); + + if (!$dir->exists()) + { + throw new BuildException("Directory '" . $this->toDir . "' does not exist"); + } + + $xslfile = $this->getStyleSheet(); + + $xsl = new DOMDocument(); + $xsl->load($xslfile->getAbsolutePath()); + + $proc = new XSLTProcessor(); + $proc->importStyleSheet($xsl); + + if ($this->format == "noframes") + { + $writer = new FileWriter(new PhingFile($this->toDir, "phpunit2-noframes.html")); + $writer->write($proc->transformToXML($document)); + $writer->close(); + } + else + { + ExtendedFileStream::registerStream(); + + // no output for the framed report + // it's all done by extension... + $dir = new PhingFile($this->toDir); + $proc->setParameter('', 'output.dir', $dir->getAbsolutePath()); + $proc->transformToXML($document); + } + } + + /** + * The main entry point + * + * @throws BuildException + */ + function main() + { + $testSuitesDoc = new DOMDocument(); + $testSuitesDoc->load($this->inFile); + + $this->transform($testSuitesDoc); + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2ResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2ResultFormatter.php new file mode 100644 index 00000000..5722c63e --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2ResultFormatter.php @@ -0,0 +1,154 @@ +. + */ + +require_once 'PHPUnit2/Framework/TestListener.php'; + +require_once 'phing/system/io/Writer.php'; + +/** + * This abstract class describes classes that format the results of a PHPUnit2 testrun. + * + * @author Michiel Rook + * @version $Id: PHPUnit2ResultFormatter.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +abstract class PHPUnit2ResultFormatter implements PHPUnit2_Framework_TestListener +{ + protected $out = NULL; + + protected $project = NULL; + + private $timer = NULL; + + private $runCount = 0; + + private $failureCount = 0; + + private $errorCount = 0; + + /** + * Sets the writer the formatter is supposed to write its results to. + */ + function setOutput(Writer $out) + { + $this->out = $out; + } + + /** + * Returns the extension used for this formatter + * + * @return string the extension + */ + function getExtension() + { + return ""; + } + + /** + * Sets the project + * + * @param Project the project + */ + function setProject(Project $project) + { + $this->project = $project; + } + + function getPreferredOutfile() + { + return ""; + } + + function startTestRun() + { + } + + function endTestRun() + { + } + + function startTestSuite(PHPUnit2_Framework_TestSuite $suite) + { + $this->runCount = 0; + $this->failureCount = 0; + $this->errorCount = 0; + + $this->timer = new Timer(); + $this->timer->start(); + } + + function endTestSuite(PHPUnit2_Framework_TestSuite $suite) + { + $this->timer->stop(); + } + + function startTest(PHPUnit2_Framework_Test $test) + { + $this->runCount++; + } + + function endTest(PHPUnit2_Framework_Test $test) + { + } + + function addError(PHPUnit2_Framework_Test $test, Exception $e) + { + $this->errorCount++; + } + + function addFailure(PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $t) + { + $this->failureCount++; + } + + function addIncompleteTest(PHPUnit2_Framework_Test $test, Exception $e) + { + } + + function getRunCount() + { + return $this->runCount; + } + + function getFailureCount() + { + return $this->failureCount; + } + + function getErrorCount() + { + return $this->errorCount; + } + + function getElapsedTime() + { + if ($this->timer) + { + return $this->timer->getElapsedTime(); + } + else + { + return 0; + } + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2Task.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2Task.php new file mode 100644 index 00000000..ffd36405 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2Task.php @@ -0,0 +1,239 @@ +. + */ + +require_once 'phing/Task.php'; +require_once 'phing/system/io/PhingFile.php'; +require_once 'phing/system/io/Writer.php'; +require_once 'phing/util/LogWriter.php'; + +/** + * Runs PHPUnit2 tests. + * + * @author Michiel Rook + * @version $Id: PHPUnit2Task.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @see BatchTest + * @since 2.1.0 + */ +class PHPUnit2Task extends Task +{ + private $batchtests = array(); + private $formatters = array(); + private $haltonerror = false; + private $haltonfailure = false; + private $failureproperty; + private $errorproperty; + private $printsummary = false; + private $testfailed = false; + private $codecoverage = false; + + /** + * Initialize Task. + * This method includes any necessary PHPUnit2 libraries and triggers + * appropriate error if they cannot be found. This is not done in header + * because we may want this class to be loaded w/o triggering an error. + */ + function init() { + include_once 'PHPUnit2/Util/Filter.php'; + if (!class_exists('PHPUnit2_Util_Filter')) { + throw new BuildException("PHPUnit2Task depends on PEAR PHPUnit2 package being installed.", $this->getLocation()); + } + + if (version_compare(PHP_VERSION, '5.0.3') < 0) { + throw new BuildException("PHPUnit2Task requires PHP version >= 5.0.3.", $this->getLocation()); + } + + // other dependencies that should only be loaded when class is actually used. + require_once 'phing/tasks/ext/phpunit2/PHPUnit2TestRunner.php'; + require_once 'phing/tasks/ext/phpunit2/BatchTest.php'; + require_once 'phing/tasks/ext/phpunit2/FormatterElement.php'; + require_once 'phing/tasks/ext/phpunit2/SummaryPHPUnit2ResultFormatter.php'; + + // add some defaults to the PHPUnit2 Filter + PHPUnit2_Util_Filter::addFileToFilter('PHPUnit2Task.php'); + PHPUnit2_Util_Filter::addFileToFilter('PHPUnit2TestRunner.php'); + PHPUnit2_Util_Filter::addFileToFilter('phing/Task.php'); + PHPUnit2_Util_Filter::addFileToFilter('phing/Target.php'); + PHPUnit2_Util_Filter::addFileToFilter('phing/Project.php'); + PHPUnit2_Util_Filter::addFileToFilter('phing/Phing.php'); + PHPUnit2_Util_Filter::addFileToFilter('phing.php'); + + } + + function setFailureproperty($value) + { + $this->failureproperty = $value; + } + + function setErrorproperty($value) + { + $this->errorproperty = $value; + } + + function setHaltonerror($value) + { + $this->haltonerror = $value; + } + + function setHaltonfailure($value) + { + $this->haltonfailure = $value; + } + + function setPrintsummary($printsummary) + { + $this->printsummary = $printsummary; + } + + function setCodecoverage($codecoverage) + { + $this->codecoverage = $codecoverage; + } + + /** + * Add a new formatter to all tests of this task. + * + * @param FormatterElement formatter element + */ + function addFormatter(FormatterElement $fe) + { + $this->formatters[] = $fe; + } + + /** + * The main entry point + * + * @throws BuildException + */ + function main() + { + $tests = array(); + + if ($this->printsummary) + { + $fe = new FormatterElement(); + $fe->setClassName('SummaryPHPUnit2ResultFormatter'); + $fe->setUseFile(false); + $this->formatters[] = $fe; + } + + foreach ($this->batchtests as $batchtest) + { + $tests = array_merge($tests, $batchtest->elements()); + } + + foreach ($this->formatters as $fe) + { + $formatter = $fe->getFormatter(); + $formatter->setProject($this->getProject()); + + if ($fe->getUseFile()) + { + $destFile = new PhingFile($fe->getToDir(), $fe->getOutfile()); + + $writer = new FileWriter($destFile->getAbsolutePath()); + + $formatter->setOutput($writer); + } + else + { + $formatter->setOutput($this->getDefaultOutput()); + } + + $formatter->startTestRun(); + } + + foreach ($tests as $test) + { + $this->execute(new PHPUnit2_Framework_TestSuite(new ReflectionClass($test))); + } + + foreach ($this->formatters as $fe) + { + $formatter = $fe->getFormatter(); + $formatter->endTestRun(); + } + + if ($this->testfailed) + { + throw new BuildException("One or more tests failed"); + } + } + + /** + * @throws BuildException + */ + private function execute($suite) + { + $runner = new PHPUnit2TestRunner($suite, $this->project); + + $runner->setCodecoverage($this->codecoverage); + + foreach ($this->formatters as $fe) + { + $formatter = $fe->getFormatter(); + + $runner->addFormatter($formatter); + } + + $runner->run(); + + $retcode = $runner->getRetCode(); + + if ($retcode == PHPUnit2TestRunner::ERRORS) { + if ($this->errorproperty) { + $this->project->setNewProperty($this->errorproperty, true); + } + if ($this->haltonerror) { + $this->testfailed = true; + } + } elseif ($retcode == PHPUnit2TestRunner::FAILURES) { + if ($this->failureproperty) { + $this->project->setNewProperty($this->failureproperty, true); + } + + if ($this->haltonfailure) { + $this->testfailed = true; + } + } + + } + + private function getDefaultOutput() + { + return new LogWriter($this); + } + + /** + * Adds a set of tests based on pattern matching. + * + * @return BatchTest a new instance of a batch test. + */ + function createBatchTest() + { + $batchtest = new BatchTest($this->getProject()); + + $this->batchtests[] = $batchtest; + + return $batchtest; + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2TestRunner.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2TestRunner.php new file mode 100644 index 00000000..bbd19f34 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2TestRunner.php @@ -0,0 +1,107 @@ +. + */ + +require_once 'PHPUnit2/Framework/TestListener.php'; +require_once 'PHPUnit2/Framework/TestResult.php'; +require_once 'PHPUnit2/Framework/TestSuite.php'; + +require_once 'phing/tasks/ext/coverage/CoverageMerger.php'; + +require_once 'phing/system/util/Timer.php'; + +/** + * Simple Testrunner for PHPUnit2 that runs all tests of a testsuite. + * + * @author Michiel Rook + * @version $Id: PHPUnit2TestRunner.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +class PHPUnit2TestRunner +{ + const SUCCESS = 0; + const FAILURES = 1; + const ERRORS = 2; + + private $test = NULL; + private $suite = NULL; + private $retCode = 0; + private $formatters = array(); + + private $codecoverage = false; + + private $project = NULL; + + function __construct(PHPUnit2_Framework_TestSuite $suite, Project $project) + { + $this->suite = $suite; + $this->project = $project; + $this->retCode = self::SUCCESS; + } + + function setCodecoverage($codecoverage) + { + $this->codecoverage = $codecoverage; + } + + function addFormatter(PHPUnit2_Framework_TestListener $formatter) + { + $this->formatters[] = $formatter; + } + + function run() + { + $res = new PHPUnit2_Framework_TestResult(); + + if ($this->codecoverage) + { + $res->collectCodeCoverageInformation(TRUE); + } + + foreach ($this->formatters as $formatter) + { + $res->addListener($formatter); + } + + $this->suite->run($res); + + if ($this->codecoverage) + { + CoverageMerger::merge($this->project, $res->getCodeCoverageInformation()); + } + + if ($res->errorCount() != 0) + { + $this->retCode = self::ERRORS; + } + + else if ($res->failureCount() != 0 || $res->notImplementedCount() != 0) + { + $this->retCode = self::FAILURES; + } + } + + function getRetCode() + { + return $this->retCode; + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2Util.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2Util.php new file mode 100644 index 00000000..f4d1f62a --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2Util.php @@ -0,0 +1,114 @@ +. + */ + +/** + * Various utility functions + * + * @author Michiel Rook + * @version $Id: PHPUnit2Util.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +class PHPUnit2Util +{ + protected static $definedClasses = array(); + + /** + * Returns the package of a class as defined in the docblock of the class using @package + * + * @param string the name of the class + * @return string the name of the package + */ + static function getPackageName($classname) + { + $reflect = new ReflectionClass($classname); + + if (preg_match('/@package[\s]+([\.\w]+)/', $reflect->getDocComment(), $matches)) + { + return $matches[1]; + } + else + { + return "default"; + } + } + + /** + * Derives the classname from a filename. + * Assumes that there is only one class defined in that particular file, and that + * the naming follows the dot-path (Java) notation scheme. + * + * @param string the filename + * @return string the name fo the class + */ + static function getClassFromFileName($filename) + { + $filename = basename($filename); + + $rpos = strrpos($filename, '.'); + + if ($rpos != -1) + { + $filename = substr($filename, 0, $rpos); + } + + return $filename; + } + + /** + * @param string the filename + * @param Path optional classpath + * @return array list of classes defined in the file + */ + static function getDefinedClasses($filename, $classpath = NULL) + { + $filename = realpath($filename); + + if (!file_exists($filename)) + { + throw new Exception("File '" . $filename . "' does not exist"); + } + + if (isset(self::$definedClasses[$filename])) + { + return self::$definedClasses[$filename]; + } + + Phing::__import($filename, $classpath); + + $declaredClasses = get_declared_classes(); + + foreach ($declaredClasses as $classname) + { + $reflect = new ReflectionClass($classname); + + self::$definedClasses[$reflect->getFilename()][] = $classname; + + if (is_array(self::$definedClasses[$reflect->getFilename()])) + { + self::$definedClasses[$reflect->getFilename()] = array_unique(self::$definedClasses[$reflect->getFilename()]); + } + } + + return self::$definedClasses[$filename]; + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PlainPHPUnit2ResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PlainPHPUnit2ResultFormatter.php new file mode 100644 index 00000000..b0a9ae58 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PlainPHPUnit2ResultFormatter.php @@ -0,0 +1,117 @@ +. + */ + +require_once 'PHPUnit2/Framework/Test.php'; +require_once 'PHPUnit2/Util/Filter.php'; + +require_once 'phing/tasks/ext/phpunit2/PHPUnit2ResultFormatter.php'; + +/** + * Prints plain text output of the test to a specified Writer. + * + * @author Michiel Rook + * @version $Id: PlainPHPUnit2ResultFormatter.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +class PlainPHPUnit2ResultFormatter extends PHPUnit2ResultFormatter +{ + private $inner = ""; + + function getExtension() + { + return ".txt"; + } + + function getPreferredOutfile() + { + return "testresults"; + } + + function startTestSuite(PHPUnit2_Framework_TestSuite $suite) + { + parent::startTestSuite($suite); + + $this->inner = ""; + } + + function endTestSuite(PHPUnit2_Framework_TestSuite $suite) + { + parent::endTestSuite($suite); + + $sb = "Testsuite: " . $suite->getName() . "\n"; + $sb.= "Tests run: " . $this->getRunCount(); + $sb.= ", Failures: " . $this->getFailureCount(); + $sb.= ", Errors: " . $this->getErrorCount(); + $sb.= ", Time elapsed: " . $this->getElapsedTime(); + $sb.= " sec\n"; + + if ($this->out != NULL) + { + $this->out->write($sb); + $this->out->write($this->inner); + } + } + + function addError(PHPUnit2_Framework_Test $test, Exception $e) + { + parent::addError($test, $e); + + $this->formatError("ERROR", $test, $e); + } + + function addFailure(PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $t) + { + parent::addFailure($test, $t); + + $this->formatError("FAILED", $test, $t); + } + + function addIncompleteTest(PHPUnit2_Framework_Test $test, Exception $e) + { + parent::addIncompleteTest($test, $e); + + $this->formatError("INCOMPLETE", $test, $e); + } + + private function formatError($type, PHPUnit2_Framework_Test $test, Exception $e) + { + if ($test != null) + { + $this->endTest($test); + } + + $this->inner.= $test->getName() . " " . $type . "\n"; + $this->inner.= $e->getMessage() . "\n"; + $this->inner.= PHPUnit2_Util_Filter::getFilteredStackTrace($e) . "\n"; + } + + function endTestRun() + { + parent::endTestRun(); + + if ($this->out != NULL) + { + $this->out->close(); + } + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/SummaryPHPUnit2ResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/SummaryPHPUnit2ResultFormatter.php new file mode 100644 index 00000000..df17d2d4 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/SummaryPHPUnit2ResultFormatter.php @@ -0,0 +1,58 @@ +. + */ + +require_once 'PHPUnit2/Framework/Test.php'; + +require_once 'phing/tasks/ext/phpunit2/PHPUnit2ResultFormatter.php'; + +/** + * Prints short summary output of the test to Phing's logging system. + * + * @author Michiel Rook + * @version $Id: SummaryPHPUnit2ResultFormatter.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +class SummaryPHPUnit2ResultFormatter extends PHPUnit2ResultFormatter +{ + function endTestSuite(PHPUnit2_Framework_TestSuite $suite) + { + parent::endTestSuite($suite); + + $sb = "Tests run: " . $this->getRunCount(); + $sb.= ", Failures: " . $this->getFailureCount(); + $sb.= ", Errors: " . $this->getErrorCount(); + $sb.= ", Time elapsed: " . $this->getElapsedTime(); + $sb.= " sec\n"; + + if ($this->out != NULL) + { + $this->out->write($sb); + $this->out->close(); + } + } + + function getExtension() + { + return NULL; + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/XMLPHPUnit2ResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/XMLPHPUnit2ResultFormatter.php new file mode 100644 index 00000000..ac2fec8f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/XMLPHPUnit2ResultFormatter.php @@ -0,0 +1,117 @@ +. + */ + +require_once 'PHPUnit2/Framework/Test.php'; +require_once 'PHPUnit2/Runner/Version.php'; + +require_once 'PHPUnit2/Util/Log/XML.php'; + +require_once 'phing/tasks/ext/phpunit2/PHPUnit2ResultFormatter.php'; + +/** + * Prints XML output of the test to a specified Writer + * + * @author Michiel Rook + * @version $Id: XMLPHPUnit2ResultFormatter.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +class XMLPHPUnit2ResultFormatter extends PHPUnit2ResultFormatter +{ + private $logger = NULL; + + function __construct() + { + $this->logger = new PHPUnit2_Util_Log_XML(); + $this->logger->setWriteDocument(false); + } + + function getExtension() + { + return ".xml"; + } + + function getPreferredOutfile() + { + return "testsuites"; + } + + function startTestSuite(PHPUnit2_Framework_TestSuite $suite) + { + parent::startTestSuite($suite); + + $this->logger->startTestSuite($suite); + } + + function endTestSuite(PHPUnit2_Framework_TestSuite $suite) + { + parent::endTestSuite($suite); + + $this->logger->endTestSuite($suite); + } + + function startTest(PHPUnit2_Framework_Test $test) + { + parent::startTest($test); + + $this->logger->startTest($test); + } + + function endTest(PHPUnit2_Framework_Test $test) + { + parent::endTest($test); + + $this->logger->endTest($test); + } + + function addError(PHPUnit2_Framework_Test $test, Exception $e) + { + parent::addError($test, $e); + + $this->logger->addError($test, $e); + } + + function addFailure(PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $t) + { + parent::addFailure($test, $t); + + $this->logger->addFailure($test, $t); + } + + function addIncompleteTest(PHPUnit2_Framework_Test $test, Exception $e) + { + parent::addIncompleteTest($test, $e); + + $this->logger->addIncompleteTest($test, $e); + } + + function endTestRun() + { + parent::endTestRun(); + + if ($this->out) + { + $this->out->write($this->logger->getXML()); + $this->out->close(); + } + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestCountResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestCountResultFormatter.php new file mode 100644 index 00000000..11e360e0 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestCountResultFormatter.php @@ -0,0 +1,52 @@ +. + */ + +require_once 'phing/tasks/ext/simpletest/SimpleTestResultFormatter.php'; + +/** + * Dummy result formatter used to count SimpleTest results + * + * @author Michiel Rook + * @version $Id: SimpleTestCountResultFormatter.php 58 2006-04-28 14:41:04Z mrook $ + * @package phing.tasks.ext.simpletest + * @since 2.2.0 + */ +class SimpleTestCountResultFormatter extends SimpleTestResultFormatter +{ + const SUCCESS = 0; + const FAILURES = 1; + const ERRORS = 2; + + function getRetCode() + { + if ($this->getExceptionCount() != 0) + { + return self::ERRORS; + } + else if ($this->getFailCount() != 0) + { + return self::FAILURES; + } + + return self::SUCCESS; + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestFormatterElement.php b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestFormatterElement.php new file mode 100644 index 00000000..fab27315 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestFormatterElement.php @@ -0,0 +1,62 @@ +. + */ + +require_once 'phing/tasks/ext/simpletest/SimpleTestPlainResultFormatter.php'; +require_once 'phing/tasks/ext/simpletest/SimpleTestSummaryResultFormatter.php'; +require_once 'phing/tasks/ext/phpunit2/FormatterElement.php'; + +/** + * Child class of "FormatterElement", overrides setType to provide other + * formatter classes for SimpleTest + * + * @author Michiel Rook + * @version $Id: SimpleTestFormatterElement.php 58 2006-04-28 14:41:04Z mrook $ + * @package phing.tasks.ext.simpletest + * @since 2.2.0 + */ +class SimpleTestFormatterElement extends FormatterElement +{ + function setType($type) + { + $this->type = $type; + + if ($this->type == "xml") + { + $destFile = new PhingFile($this->toDir, 'testsuites.xml'); + //$this->formatter = new SimpleTestXmlResultFormatter(); + } + else + if ($this->type == "plain") + { + $this->formatter = new SimpleTestPlainResultFormatter(); + } + else + if ($this->type == "summary") + { + $this->formatter = new SimpleTestSummaryResultFormatter(); + } + else + { + throw new BuildException("Formatter '" . $this->type . "' not implemented"); + } + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestPlainResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestPlainResultFormatter.php new file mode 100644 index 00000000..f84ca815 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestPlainResultFormatter.php @@ -0,0 +1,95 @@ +. + */ + +require_once 'phing/tasks/ext/simpletest/SimpleTestResultFormatter.php'; + +/** + * Prints plain text output of the test to a specified Writer. + * + * @author Michiel Rook + * @version $Id: SimpleTestPlainResultFormatter.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.simpletest + * @since 2.2.0 + */ +class SimpleTestPlainResultFormatter extends SimpleTestResultFormatter +{ + private $inner = ""; + + function getExtension() + { + return ".txt"; + } + + function getPreferredOutfile() + { + return "testresults"; + } + + function paintCaseStart($test_name) + { + parent::paintCaseStart($test_name); + + $this->inner = ""; + } + + function paintCaseEnd($test_name) + { + parent::paintCaseEnd($test_name); + + /* Only count suites where more than one test was run */ + if ($this->getRunCount()) + { + $sb.= "Testsuite: $test_name\n"; + $sb.= "Tests run: " . $this->getRunCount(); + $sb.= ", Failures: " . $this->getFailureCount(); + $sb.= ", Errors: " . $this->getErrorCount(); + $sb.= ", Time elapsed: " . $this->getElapsedTime(); + $sb.= " sec\n"; + + if ($this->out != NULL) + { + $this->out->write($sb); + $this->out->write($this->inner); + } + } + } + + function paintError($message) + { + parent::paintError($message); + + $this->formatError("ERROR", $message); + } + + function paintFail($message) + { + parent::paintFail($message); + + $this->formatError("FAILED", $message); + } + + private function formatError($type, $message) + { + $this->inner.= $this->getTestName() . " " . $type . "\n"; + $this->inner.= $message . "\n"; + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestResultFormatter.php new file mode 100644 index 00000000..7f94892f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestResultFormatter.php @@ -0,0 +1,162 @@ +. + */ + +require_once 'simpletest/scorer.php'; + +require_once 'phing/system/io/Writer.php'; + +/** + * This abstract class describes classes that format the results of a SimpleTest testrun. + * + * @author Michiel Rook + * @version $Id: SimpleTestResultFormatter.php 58 2006-04-28 14:41:04Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.2.0 + */ +abstract class SimpleTestResultFormatter extends SimpleReporter +{ + protected $out = NULL; + + protected $project = NULL; + + private $timer = NULL; + + private $runCount = 0; + + private $failureCount = 0; + + private $errorCount = 0; + + private $currentTest = ""; + + /** + * Sets the writer the formatter is supposed to write its results to. + */ + function setOutput(Writer $out) + { + $this->out = $out; + } + + /** + * Returns the extension used for this formatter + * + * @return string the extension + */ + function getExtension() + { + return ""; + } + + /** + * Sets the project + * + * @param Project the project + */ + function setProject(Project $project) + { + $this->project = $project; + } + + function getPreferredOutfile() + { + return ""; + } + + function paintMethodStart($test_name) + { + parent::paintMethodStart($test_name); + + $this->currentTest = $test_name; + } + + function paintMethodEnd($test_name) + { + parent::paintMethodEnd($test_name); + + $this->runCount++; + } + + function paintCaseStart($test_name) + { + parent::paintCaseStart($test_name); + + $this->runCount = 0; + $this->failureCount = 0; + $this->errorCount = 0; + + $this->timer = new Timer(); + $this->timer->start(); + } + + function paintCaseEnd($test_name) + { + parent::paintCaseEnd($test_name); + + $this->timer->stop(); + } + + function paintError($message) + { + parent::paintError($message); + + $this->errorCount++; + } + + function paintFail($message) + { + parent::paintFail($message); + + $this->failureCount++; + } + + function getRunCount() + { + return $this->runCount; + } + + function getFailureCount() + { + return $this->failureCount; + } + + function getErrorCount() + { + return $this->errorCount; + } + + function getTestName() + { + return $this->currentTest; + } + + function getElapsedTime() + { + if ($this->timer) + { + return $this->timer->getElapsedTime(); + } + else + { + return 0; + } + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestSummaryResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestSummaryResultFormatter.php new file mode 100644 index 00000000..79494bc9 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestSummaryResultFormatter.php @@ -0,0 +1,54 @@ +. + */ + +require_once 'phing/tasks/ext/simpletest/SimpleTestResultFormatter.php'; + +/** + * Prints short summary output of the test to Phing's logging system. + * + * @author Michiel Rook + * @version $Id: SimpleTestSummaryResultFormatter.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.simpletest + * @since 2.2.0 + */ +class SimpleTestSummaryResultFormatter extends SimpleTestResultFormatter +{ + function paintCaseEnd($test_name) + { + parent::paintCaseEnd($test_name); + + /* Only count suites where more than one test was run */ + if ($this->getRunCount()) + { + $sb.= "Tests run: " . $this->getRunCount(); + $sb.= ", Failures: " . $this->getFailureCount(); + $sb.= ", Errors: " . $this->getErrorCount(); + $sb.= ", Time elapsed: " . $this->getElapsedTime(); + $sb.= " sec\n"; + + if ($this->out != NULL) + { + $this->out->write($sb); + } + } + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestTask.php b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestTask.php new file mode 100644 index 00000000..6aede68f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestTask.php @@ -0,0 +1,238 @@ +. + */ + +require_once 'phing/Task.php'; +require_once 'phing/system/io/PhingFile.php'; +require_once 'phing/system/io/Writer.php'; +require_once 'phing/util/LogWriter.php'; + +/** + * Runs SimpleTest tests. + * + * @author Michiel Rook + * @version $Id: SimpleTestTask.php 58 2006-04-28 14:41:04Z mrook $ + * @package phing.tasks.ext.simpletest + * @since 2.2.0 + */ +class SimpleTestTask extends Task +{ + private $formatters = array(); + private $haltonerror = false; + private $haltonfailure = false; + private $failureproperty; + private $errorproperty; + private $printsummary = false; + private $testfailed = false; + + /** + * Initialize Task. + * This method includes any necessary SimpleTest libraries and triggers + * appropriate error if they cannot be found. This is not done in header + * because we may want this class to be loaded w/o triggering an error. + */ + function init() { + @include_once 'simpletest/scorer.php'; + + if (!class_exists('SimpleReporter')) { + throw new BuildException("SimpleTestTask depends on SimpleTest package being installed.", $this->getLocation()); + } + + require_once 'simpletest/reporter.php'; + require_once 'simpletest/xml.php'; + require_once 'simpletest/test_case.php'; + require_once 'phing/tasks/ext/simpletest/SimpleTestCountResultFormatter.php'; + require_once 'phing/tasks/ext/simpletest/SimpleTestFormatterElement.php'; + } + + function setFailureproperty($value) + { + $this->failureproperty = $value; + } + + function setErrorproperty($value) + { + $this->errorproperty = $value; + } + + function setHaltonerror($value) + { + $this->haltonerror = $value; + } + + function setHaltonfailure($value) + { + $this->haltonfailure = $value; + } + + function setPrintsummary($printsummary) + { + $this->printsummary = $printsummary; + } + + /** + * Add a new formatter to all tests of this task. + * + * @param SimpleTestFormatterElement formatter element + */ + function addFormatter(SimpleTestFormatterElement $fe) + { + $this->formatters[] = $fe; + } + + /** + * Add a new fileset containing the XML results to aggregate + * + * @param FileSet the new fileset containing XML results. + */ + function addFileSet(FileSet $fileset) + { + $this->filesets[] = $fileset; + } + + /** + * Iterate over all filesets and return the filename of all files + * that end with .php. + * + * @return array an array of filenames + */ + private function getFilenames() + { + $filenames = array(); + + foreach ($this->filesets as $fileset) + { + $ds = $fileset->getDirectoryScanner($this->project); + $ds->scan(); + + $files = $ds->getIncludedFiles(); + + foreach ($files as $file) + { + if (strstr($file, ".php")) + { + $filenames[] = $ds->getBaseDir() . "/" . $file; + } + } + } + + return $filenames; + } + + /** + * The main entry point + * + * @throws BuildException + */ + function main() + { + $group = new GroupTest(); + + $filenames = $this->getFilenames(); + + foreach ($filenames as $testfile) + { + $group->addTestFile($testfile); + } + + if ($this->printsummary) + { + $fe = new SimpleTestFormatterElement(); + $fe->setType('summary'); + $fe->setUseFile(false); + $this->formatters[] = $fe; + } + + foreach ($this->formatters as $fe) + { + $formatter = $fe->getFormatter(); + $formatter->setProject($this->getProject()); + + if ($fe->getUseFile()) + { + $destFile = new PhingFile($fe->getToDir(), $fe->getOutfile()); + + $writer = new FileWriter($destFile->getAbsolutePath()); + + $formatter->setOutput($writer); + } + else + { + $formatter->setOutput($this->getDefaultOutput()); + } + } + + $this->execute($group); + + if ($this->testfailed) + { + throw new BuildException("One or more tests failed"); + } + } + + private function execute($suite) + { + $counter = new SimpleTestCountResultFormatter(); + $reporter = new MultipleReporter(); + $reporter->attachReporter($counter); + + foreach ($this->formatters as $fe) + { + $formatter = $fe->getFormatter(); + + $reporter->attachReporter($formatter); + } + + $suite->run($reporter); + + $retcode = $counter->getRetCode(); + + if ($retcode == SimpleTestCountResultFormatter::ERRORS) + { + if ($this->errorproperty) + { + $this->project->setNewProperty($this->errorproperty, true); + } + + if ($this->haltonerror) + { + $this->testfailed = true; + } + } + elseif ($retcode == SimpleTestCountResultFormatter::FAILURES) + { + if ($this->failureproperty) + { + $this->project->setNewProperty($this->failureproperty, true); + } + + if ($this->haltonfailure) + { + $this->testfailed = true; + } + } + } + + private function getDefaultOutput() + { + return new LogWriter($this); + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/svn/SvnBaseTask.php b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnBaseTask.php new file mode 100644 index 00000000..71e3ba2e --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnBaseTask.php @@ -0,0 +1,180 @@ +. + */ + +include_once 'phing/Task.php'; + +/** + * Send a message by mail() + * + * The build process is a success... + * + * @author Francois Harvey at SecuriWeb (http://www.securiweb.net) + * @version $Id: SvnBaseTask.php 38 2006-03-09 14:05:11Z mrook $ + * @package phing.tasks.ext + */ +abstract class SvnBaseTask extends Task +{ + private $workingCopy = ""; + + private $repositoryUrl = ""; + + private $svnPath = "/usr/bin/svn"; + + private $svn = NULL; + + private $mode = ""; + + private $svnArgs = array(); + + /** + * Initialize Task. + * This method includes any necessary SVN libraries and triggers + * appropriate error if they cannot be found. This is not done in header + * because we may want this class to be loaded w/o triggering an error. + */ + function init() { + include_once 'VersionControl/SVN.php'; + if (!class_exists('VersionControl_SVN')) { + throw new Exception("SvnLastRevisionTask depends on PEAR VersionControl_SVN package being installed."); + } + } + + /** + * Sets the path to the workingcopy + */ + function setWorkingCopy($workingCopy) + { + $this->workingCopy = $workingCopy; + } + + /** + * Returns the path to the workingcopy + */ + function getWorkingCopy() + { + return $this->workingCopy; + } + + /** + * Sets the path/URI to the repository + */ + function setRepositoryUrl($repositoryUrl) + { + $this->repositoryUrl = $repositoryUrl; + } + + /** + * Returns the path/URI to the repository + */ + function getRepositoryUrl() + { + return $this->repositoryUrl; + } + + /** + * Sets the path to the SVN executable + */ + function setSvnPath($svnPath) + { + $this->svnPath = $svnPath; + } + + /** + * Returns the path to the SVN executable + */ + function getSvnPath() + { + return $this->svnPath; + } + + /** + * Creates a VersionControl_SVN class based on $mode + * + * @param string The SVN mode to use (info, export, checkout, ...) + * @throws BuildException + */ + protected function setup($mode) + { + $this->mode = $mode; + + // Set up runtime options. Will be passed to all + // subclasses. + $options = array('fetchmode' => VERSIONCONTROL_SVN_FETCHMODE_ASSOC, 'svn_path' => $this->getSvnPath()); + + // Pass array of subcommands we need to factory + $this->svn = VersionControl_SVN::factory($mode, $options); + + if (!empty($this->repositoryUrl)) + { + $this->svnArgs = array($this->repositoryUrl); + } + else + if (!empty($this->workingCopy)) + { + if (is_dir($this->workingCopy)) + { + if (in_array(".svn", scandir($this->workingCopy))) + { + $this->svnArgs = array($this->workingCopy); + } + else + { + throw new BuildException("'".$this->workingCopy."' doesn't seem to be a working copy"); + } + } + else + { + throw new BuildException("'".$this->workingCopy."' is not a directory"); + } + } + } + + /** + * Executes the constructed VersionControl_SVN instance + * + * @param array Additional arguments to pass to SVN. + * @param array Switches to pass to SVN. + * @return string Output generated by SVN. + */ + protected function run($args = array(), $switches = array()) + { + $svnstack = PEAR_ErrorStack::singleton('VersionControl_SVN'); + + $tempArgs = $this->svnArgs; + + $tempArgs = array_merge($tempArgs, $args); + + if ($output = $this->svn->run($tempArgs, $switches)) + { + return $output; + } + else + { + if (count($errs = $svnstack->getErrors())) + { + $err = current($errs); + + throw new BuildException("Failed to run the 'svn " . $this->mode . "' command: " . $err['message']); + } + } + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/svn/SvnExportTask.php b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnExportTask.php new file mode 100644 index 00000000..7cb6c897 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnExportTask.php @@ -0,0 +1,68 @@ +. + */ + +require_once 'phing/Task.php'; +require_once 'phing/tasks/ext/svn/SvnBaseTask.php'; + +/** + * Exports/checks out a repository to a local directory + * + * @author Michiel Rook + * @version $Id: SvnExportTask.php 37 2006-03-09 14:04:22Z mrook $ + * @package phing.tasks.ext.svn + * @see VersionControl_SVN + * @since 2.1.0 + */ +class SvnExportTask extends SvnBaseTask +{ + private $toDir = ""; + + /** + * Sets the path to export/checkout to + */ + function setToDir($toDir) + { + $this->toDir = $toDir; + } + + /** + * Returns the path to export/checkout to + */ + function getToDir() + { + return $this->toDir; + } + + /** + * The main entry point + * + * @throws BuildException + */ + function main() + { + $this->setup('export'); + + $this->log("Exporting SVN repository to '" . $this->toDir . "'"); + + $this->run(array($this->toDir)); + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/svn/SvnLastRevisionTask.php b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnLastRevisionTask.php new file mode 100644 index 00000000..e45ac50c --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnLastRevisionTask.php @@ -0,0 +1,75 @@ +. + */ + +require_once 'phing/Task.php'; +require_once 'phing/tasks/ext/svn/SvnBaseTask.php'; + +/** + * Stores the number of the last revision of a workingcopy in a property + * + * @author Michiel Rook + * @version $Id: SvnLastRevisionTask.php 37 2006-03-09 14:04:22Z mrook $ + * @package phing.tasks.ext.svn + * @see VersionControl_SVN + * @since 2.1.0 + */ +class SvnLastRevisionTask extends SvnBaseTask +{ + private $propertyName = "svn.lastrevision"; + + /** + * Sets the name of the property to use + */ + function setPropertyName($propertyName) + { + $this->propertyName = $propertyName; + } + + /** + * Returns the name of the property to use + */ + function getPropertyName() + { + return $this->propertyName; + } + + /** + * The main entry point + * + * @throws BuildException + */ + function main() + { + $this->setup('info'); + + $output = $this->run(); + + if (preg_match('/Rev:[\s]+([\d]+)/', $output, $matches)) + { + $this->project->setProperty($this->getPropertyName(), $matches[1]); + } + else + { + throw new BuildException("Failed to parse the output of 'svn info'."); + } + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/system/AdhocTask.php b/buildscripts/phing/classes/phing/tasks/system/AdhocTask.php new file mode 100644 index 00000000..e4c291a1 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/AdhocTask.php @@ -0,0 +1,88 @@ +. + */ + +require_once 'phing/Task.php'; + +/** + * Abstract class for creating adhoc Phing components in buildfile. + * + * By itself this class can be used to declare a single class within your buildfile. + * You can then reference this class in any task that takes custom classes (selectors, + * mappers, filters, etc.) + * + * Subclasses exist for conveniently declaring and registering tasks and types. + * + * @author Hans Lellelid + * @version $Revision: 1.6 $ + * @package phing.tasks.system + */ +class AdhocTask extends Task { + + /** + * The PHP script + * @var string + */ + protected $script; + + protected $newClasses = array(); + + /** + * Main entry point + */ + public function main() { + $this->execute(); + if ($this->newClasses) { + foreach($this->newClasses as $classname) { + $this->log("Added adhoc class " . $classname, PROJECT_MSG_VERBOSE); + } + } else { + $this->log("Adhoc task executed but did not result in any new classes.", PROJECT_MSG_VERBOSE); + } + } + + /** + * Get array of names of newly defined classes. + * @return array + */ + protected function getNewClasses() { + return $this->newClasses; + } + + /** + * Load the adhoc class, and perform any core validation. + * @return string The classname of the ProjectComponent class. + * @throws BuildException - if more than one class is defined. + */ + protected function execute() { + $classes = get_declared_classes(); + eval($this->script); + $this->newClasses = array_diff(get_declared_classes(), $classes); + } + + /** + * Set the script. + * @param string $script + */ + public function addText($script) { + $this->script = $script; + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/AdhocTaskdefTask.php b/buildscripts/phing/classes/phing/tasks/system/AdhocTaskdefTask.php new file mode 100644 index 00000000..ea336f84 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/AdhocTaskdefTask.php @@ -0,0 +1,90 @@ +. + */ + +require_once 'phing/tasks/system/AdhocTask.php'; + +/** + * A class for creating adhoc tasks in build file. + * + * + * bar = $bar; + * } + * + * function main() { + * $this->log("In FooTest: " . $this->bar); + * } + * } + * + * ]]> + * + * + * + * + * @author Hans Lellelid + * @version $Revision: 1.5 $ + * @package phing.tasks.system + */ +class AdhocTaskdefTask extends AdhocTask { + + /** + * The tag that refers to this task. + */ + private $name; + + /** + * Set the tag that will represent this adhoc task/type. + * @param string $name + */ + public function setName($name) { + $this->name = $name; + } + + /** Main entry point */ + public function main() { + if ($this->name === null) { + throw new BuildException("The name attribute is required for adhoc task definition.",$this->location); + } + + $this->execute(); + + $classes = $this->getNewClasses(); + if (count($classes) !== 1) { + throw new BuildException("You must define one (and only one) class for AdhocTaskdefTask."); + } + $classname = array_shift($classes); + + // instantiate it to make sure it is an instance of Task + $t = new $classname(); + if (!($t instanceof Task)) { + throw new BuildException("The adhoc class you defined must be an instance of phing.Task", $this->location); + } + + $this->log("Task " . $this->name . " will be handled by class " . $classname, PROJECT_MSG_VERBOSE); + $this->project->addTaskDefinition($this->name, $classname); + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/AdhocTypedefTask.php b/buildscripts/phing/classes/phing/tasks/system/AdhocTypedefTask.php new file mode 100644 index 00000000..b836ad93 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/AdhocTypedefTask.php @@ -0,0 +1,71 @@ +. + */ + +require_once 'phing/tasks/system/AdhocTask.php'; + +/** + * A class for creating adhoc datatypes in build file. + * + * @author Hans Lellelid + * @version $Revision: 1.4 $ + * @package phing.tasks.system + */ +class AdhocTypedefTask extends AdhocTask { + + /** + * The tag that refers to this task. + */ + private $name; + + /** + * Set the tag that will represent this adhoc task/type. + * @param string $name + */ + public function setName($name) { + $this->name = $name; + } + + /** Main entry point */ + public function main() { + + if ($this->name === null) { + throw new BuildException("The name attribute is required for adhoc task definition.",$this->location); + } + + $this->execute(); + + $classes = $this->getNewClasses(); + if (count($classes) !== 1) { + throw new BuildException("You must define one (and only one) class for AdhocTypedefTask."); + } + $classname = array_shift($classes); + + // instantiate it to make sure it is an instance of ProjectComponent + $t = new $classname(); + if (!($t instanceof ProjectComponent)) { + throw new BuildException("The adhoc class you defined must be an instance of phing.ProjectComponent", $this->location); + } + + $this->log("Datatype " . $this->name . " will be handled by class " . $classname, PROJECT_MSG_VERBOSE); + $this->project->addDataTypeDefinition($this->name, $classname); + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/AppendTask.php b/buildscripts/phing/classes/phing/tasks/system/AppendTask.php new file mode 100644 index 00000000..feb797cf --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/AppendTask.php @@ -0,0 +1,240 @@ +. + */ + +require_once 'phing/Task.php'; +include_once 'phing/types/FileList.php'; +include_once 'phing/types/FileSet.php'; + +/** + * Appends text, contents of a file or set of files defined by a filelist to a destination file. + * + * + * + * + * OR + * + * + * + * + * + * OR + * + * + * + * + * + * + * + * + * + * + * + * @package phing.tasks.system + * @version $Revision: 1.14 $ + */ +class AppendTask extends Task { + + /** Append stuff to this file. */ + private $to; + + /** Explicit file to append. */ + private $file; + + /** Any filesets of files that should be appended. */ + private $filesets = array(); + + /** Any filelists of files that should be appended. */ + private $filelists = array(); + + /** Any filters to be applied before append happens. */ + private $filterChains = array(); + + /** Text to append. (cannot be used in conjunction w/ files or filesets) */ + private $text; + + /** Sets specific file to append. */ + function setFile(PhingFile $f) { + $this->file = $f; + } + + /** + * Set target file to append to. + * @deprecated Will be removed with final release. + */ + function setTo(PhingFile $f) { + $this->log("The 'to' attribute is deprecated in favor of 'destFile'; please update your code.", PROJECT_MSG_WARN); + $this->to = $f; + } + + /** + * The more conventional naming for method to set destination file. + * @param PhingFile $f + */ + function setDestFile(PhingFile $f) { + $this->to = $f; + } + + /** + * Supports embedded element. + * @return FileList + */ + function createFileList() { + $num = array_push($this->filelists, new FileList()); + return $this->filelists[$num-1]; + } + + /** + * Nested creator, adds a set of files (nested attribute). + * This is for when you don't care what order files get appended. + * @return FileSet + */ + function createFileSet() { + $num = array_push($this->filesets, new FileSet()); + return $this->filesets[$num-1]; + } + + /** + * Creates a filterchain + * + * @return FilterChain The created filterchain object + */ + function createFilterChain() { + $num = array_push($this->filterChains, new FilterChain($this->project)); + return $this->filterChains[$num-1]; + } + + /** + * Sets text to append. (cannot be used in conjunction w/ files or filesets). + * @param string $txt + */ + function setText($txt) { + $this->text = (string) $txt; + } + + /** + * Sets text to append. Supports CDATA. + * @param string $txt + */ + function addText($txt) { + $this->text = (string) $txt; + } + + + /** Append the file(s). */ + function main() { + + if ($this->to === null) { + throw new BuildException("You must specify the 'destFile' attribute"); + } + + if ($this->file === null && empty($this->filelists) && empty($this->filesets) && $this->text === null) { + throw new BuildException("You must specify a file, use a filelist, or specify a text value."); + } + + if ($this->text !== null && ($this->file !== null || !empty($this->filelists))) { + throw new BuildException("Cannot use text attribute in conjunction with file or filelists."); + } + + // create a filwriter to append to "to" file. + $writer = new FileWriter($this->to, $append=true); + + if ($this->text !== null) { + + // simply append the text + $this->log("Appending string to " . $this->to->getPath()); + + // for debugging primarily, maybe comment + // out for better performance(?) + $lines = explode("\n", $this->text); + foreach($lines as $line) { + $this->log($line, PROJECT_MSG_VERBOSE); + } + + $writer->write($this->text); + + } else { + + // append explicitly-specified file + if ($this->file !== null) { + try { + $this->appendFile($writer, $this->file); + } catch (Exception $ioe) { + $this->log("Unable to append contents of file " . $this->file->getAbsolutePath() . ": " . $ioe->getMessage(), PROJECT_MSG_WARN); + } + } + + // append the files in the filelists + foreach($this->filelists as $fl) { + try { + $files = $fl->getFiles($this->project); + $this->appendFiles($writer, $files, $fl->getDir($this->project)); + } catch (BuildException $be) { + $this->log($be->getMessage(), PROJECT_MSG_WARN); + } + } + + // append any files in filesets + foreach($this->filesets as $fs) { + try { + $files = $fs->getDirectoryScanner($this->project)->getIncludedFiles(); + $this->appendFiles($writer, $files, $fs->getDir($this->project)); + } catch (BuildException $be) { + $this->log($be->getMessage(), PROJECT_MSG_WARN); + } + } + + } // if ($text ) {} else {} + + $writer->close(); + } + + /** + * Append an array of files in a directory. + * @param FileWriter $writer The FileWriter that is appending to target file. + * @param array $files array of files to delete; can be of zero length + * @param PhingFile $dir directory to work from + */ + private function appendFiles(FileWriter $writer, $files, PhingFile $dir) { + if (!empty($files)) { + $this->log("Attempting to append " . count($files) . " files" .($dir !== null ? ", using basedir " . $dir->getPath(): "")); + $basenameSlot = Register::getSlot("task.append.current_file"); + $pathSlot = Register::getSlot("task.append.current_file.path"); + foreach($files as $filename) { + try { + $f = new PhingFile($dir, $filename); + $basenameSlot->setValue($filename); + $pathSlot->setValue($f->getPath()); + $this->appendFile($writer, $f); + } catch (Exception $ioe) { + $this->log("Unable to append contents of file " . $f->getAbsolutePath() . ": " . $ioe->getMessage(), PROJECT_MSG_WARN); + } + } + } // if !empty + } + + private function appendFile(FileWriter $writer, PhingFile $f) { + $in = FileUtils::getChainedReader(new FileReader($f), $this->filterChains, $this->project); + while(-1 !== ($buffer = $in->read())) { // -1 indicates EOF + $writer->write($buffer); + } + $this->log("Appending contents of " . $f->getPath() . " to " . $this->to->getPath()); + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/AvailableTask.php b/buildscripts/phing/classes/phing/tasks/system/AvailableTask.php new file mode 100644 index 00000000..76de3e40 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/AvailableTask.php @@ -0,0 +1,132 @@ +. + */ + +require_once 'phing/Task.php'; +include_once 'phing/tasks/system/condition/ConditionBase.php'; + +/** + * task. + * + * Note: implements condition interface (see condition/Condition.php) + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.11 $ + * @package phing.tasks.system + */ +class AvailableTask extends Task { + + /** Property to check for. */ + private $property; + + /** Value property should be set to. */ + private $value = "true"; + + /** Resource to check for */ + private $resource; + + private $type = null; + private $filepath = null; + + function setProperty($property) { + $this->property = (string) $property; + } + + function setValue($value) { + $this->value = (string) $value; + } + + function setFile(PhingFile $file) { + $this->file = $file; + } + + function setResource($resource) { + $this->resource = (string) $resource; + } + + function setType($type) { + $this->type = (string) strtolower($type); + } + + function main() { + if ($this->property === null) { + throw new BuildException("property attribute is required", $this->location); + } + if ($this->evaluate()) { + $this->project->setProperty($this->property, $this->value); + } + } + + function evaluate() { + if ($this->file === null && $this->resource === null) { + throw new BuildException("At least one of (file|resource) is required", $this->location); + } + + if ($this->type !== null && ($this->type !== "file" && $this->type !== "dir")) { + throw new BuildException("Type must be one of either dir or file", $this->location); + } + + if (($this->file !== null) && !$this->_checkFile()) { + $this->log("Unable to find " . $this->file->__toString() . " to set property " . $this->property, PROJECT_MSG_VERBOSE); + return false; + } + + if (($this->resource !== null) && !$this->_checkResource($this->resource)) { + $this->log("Unable to load resource " . $this->resource . " to set property " . $this->property, PROJECT_MSG_VERBOSE); + return false; + } + + return true; + } + + // this is prepared for the path type + function _checkFile() { + if ($this->filepath === null) { + return $this->_checkFile1($this->file); + } else { + $paths = $this->filepath->listDir(); + for($i=0,$pcnt=count($paths); $i < $pcnt; $i++) { + $this->log("Searching " . $paths[$i], PROJECT_MSG_VERBOSE); + $tmp = new PhingFile($paths[$i], $this->file->getName()); + if($tmp->isFile()) { + return true; + } + } + } + return false; + } + + function _checkFile1($file) { + if ($this->type !== null) { + if ($this->type === "dir") { + return $file->isDirectory(); + } else if ($this->type === "file") { + return $file->isFile(); + } + } + return $file->exists(); + } + + function _checkResource($resource) { + return $this->_checkFile1(new PhingFile(Phing::getResourcePath($resource))); + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/ChmodTask.php b/buildscripts/phing/classes/phing/tasks/system/ChmodTask.php new file mode 100644 index 00000000..80470dea --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/ChmodTask.php @@ -0,0 +1,177 @@ +. + */ + +require_once 'phing/Task.php'; +include_once 'phing/types/FileSet.php'; + +/** + * Task that changes the permissions on a file/directory. + * + * @author Manuel Holtgrewe + * @author Hans Lellelid + * @version $Revision: 1.12 $ + * @package phing.tasks.system + */ +class ChmodTask extends Task { + + private $file; + + private $mode; + + private $filesets = array(); + + private $filesystem; + + private $quiet = false; + private $failonerror = true; + + /** + * This flag means 'note errors to the output, but keep going' + * @see setQuiet() + */ + function setFailonerror($bool) { + $this->failonerror = $bool; + } + + /** + * Set quiet mode, which suppresses warnings if chmod() fails. + * @see setFailonerror() + */ + function setQuiet($bool) { + $this->quiet = $bool; + if ($this->quiet) { + $this->failonerror = false; + } + } + + /** + * Sets a single source file to touch. If the file does not exist + * an empty file will be created. + */ + function setFile(PhingFile $file) { + $this->file = $file; + } + + function setMode($str) { + $this->mode = $str; + } + + /** + * Nested creator, adds a set of files (nested fileset attribute). + */ + function createFileSet() { + $num = array_push($this->filesets, new FileSet()); + return $this->filesets[$num-1]; + } + + /** + * Execute the touch operation. + * @return void + */ + function main() { + // Check Parameters + $this->checkParams(); + $this->chmod(); + } + + /** + * Ensure that correct parameters were passed in. + * @return void + */ + private function checkParams() { + + if ($this->file === null && empty($this->filesets)) { + throw new BuildException("Specify at least one source - a file or a fileset."); + } + + if ($this->mode === null) { + throw new BuildException("You have to specify an octal mode for chmod."); + } + + // check for mode to be in the correct format + if (!preg_match('/^([0-7]){3,4}$/', $this->mode)) { + throw new BuildException("You have specified an invalid mode."); + } + + } + + /** + * Does the actual work. + * @return void + */ + private function chmod() { + + if (strlen($this->mode) === 4) { + $mode = octdec($this->mode); + } else { + // we need to prepend the 0 before converting + $mode = octdec("0". $this->mode); + } + + // one file + if ($this->file !== null) { + $this->chmodFile($this->file, $mode); + } + + // filesets + foreach($this->filesets as $fs) { + + $ds = $fs->getDirectoryScanner($this->project); + $fromDir = $fs->getDir($this->project); + + $srcFiles = $ds->getIncludedFiles(); + $srcDirs = $ds->getIncludedDirectories(); + + for ($j = 0, $filecount = count($srcFiles); $j < $filecount; $j++) { + $this->chmodFile(new PhingFile($fromDir, $srcFiles[$j]), $mode); + } + + for ($j = 0, $dircount = count($srcDirs); $j < $dircount; $j++) { + $this->chmodFile(new PhingFile($fromDir, $srcDirs[$j]), $mode); + } + } + + } + + /** + * Actually change the mode for the file. + * @param PhingFile $file + * @param int $mode + */ + private function chmodFile(PhingFile $file, $mode) { + if ( !$file->exists() ) { + throw new BuildException("The file " . $file->__toString() . " does not exist"); + } + + try { + $file->setMode($mode); + $this->log("Changed file mode on '" . $file->__toString() ."' to " . vsprintf("%o", $mode)); + } catch (Exception $e) { + if($this->failonerror) { + throw $e; + } else { + $this->log($e->getMessage(), $this->quiet ? PROJECT_MSG_VERBOSE : PROJECT_MSG_WARN); + } + } + } + +} + diff --git a/buildscripts/phing/classes/phing/tasks/system/ConditionTask.php b/buildscripts/phing/classes/phing/tasks/system/ConditionTask.php new file mode 100644 index 00000000..fe6ee60b --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/ConditionTask.php @@ -0,0 +1,74 @@ +. +*/ + +require_once 'phing/tasks/system/condition/ConditionBase.php'; + +/** + * task as a generalization of + * + *

        This task supports boolean logic as well as pluggable conditions + * to decide, whether a property should be set.

        + * + *

        This task does not extend Task to take advantage of + * ConditionBase.

        + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.7 $ $Date: 2006-04-28 10:49:47 -0400 (Fri, 28 Apr 2006) $ + * @access public + * @package phing.tasks.system + */ +class ConditionTask extends ConditionBase { + + private $property; + private $value = "true"; + + /** + * The name of the property to set. Required. + */ + function setProperty($p) { + $this->property = $p; + } + + /** + * The value for the property to set. Defaults to "true". + */ + function setValue($v) { + $this->value = $v; + } + + /** + * See whether our nested condition holds and set the property. + */ + function main() { + + if ($this->countConditions() > 1) { + throw new BuildException("You must not nest more than one condition into "); + } + if ($this->countConditions() < 1) { + throw new BuildException("You must nest a condition into "); + } + $cs = $this->getIterator(); + if ($cs->current()->evaluate()) { + $this->project->setProperty($this->property, $this->value); + } + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/CopyTask.php b/buildscripts/phing/classes/phing/tasks/system/CopyTask.php new file mode 100644 index 00000000..c5e4c2a5 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/CopyTask.php @@ -0,0 +1,401 @@ +. + */ + +require_once 'phing/Task.php'; +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/util/FileUtils.php'; +include_once 'phing/util/SourceFileScanner.php'; +include_once 'phing/mappers/IdentityMapper.php'; +include_once 'phing/mappers/FlattenMapper.php'; + +/** + * A phing copy task. Copies a file or directory to a new file + * or directory. Files are only copied if the source file is newer + * than the destination file, or when the destination file does not + * exist. It is possible to explictly overwrite existing files. + * + * @author Andreas Aderhold, andi@binarycloud.com + * @version $Revision: 1.16 $ $Date: 2006-04-28 10:49:47 -0400 (Fri, 28 Apr 2006) $ + * @package phing.tasks.system + */ +class CopyTask extends Task { + + protected $file = null; // the source file (from xml attribute) + protected $destFile = null; // the destiantion file (from xml attribute) + protected $destDir = null; // the destination dir (from xml attribute) + protected $overwrite = false; // overwrite destination (from xml attribute) + protected $preserveLMT = true; // sync timestamps (from xml attribute) + protected $includeEmpty = true; // include empty dirs? (from XML) + protected $flatten = false; // apply the FlattenMapper right way (from XML) + protected $mapperElement = null; + + protected $fileCopyMap = array(); // asoc array containing mapped file names + protected $dirCopyMap = array(); // asoc array containing mapped file names + protected $fileUtils = null; // a instance of fileutils + protected $filesets = array(); // all fileset objects assigned to this task + protected $filterChains = array(); // all filterchains objects assigned to this task + + protected $verbosity = PROJECT_MSG_VERBOSE; + + /** + * Sets up this object internal stuff. i.e. the Fileutils instance + * + * @return object The CopyTask instnace + * @access public + */ + function __construct() { + $this->fileUtils = new FileUtils(); + } + + /** + * Set the overwrite flag. IntrospectionHelper takes care of + * booleans in set* methods so we can assume that the right + * value (boolean primitive) is coming in here. + * + * @param boolean Overwrite the destination file(s) if it/they already exist + * @return void + * @access public + */ + function setOverwrite($bool) { + $this->overwrite = (boolean) $bool; + } + + /** + * Used to force listing of all names of copied files. + * @param boolean $verbosity + */ + function setVerbose($verbosity) { + if ($verbosity) { + $this->verbosity = PROJECT_MSG_INFO; + } else { + $this->verbosity = PROJECT_MSG_VERBOSE; + } + } + + /** + * Set the preserve timestmap flag. IntrospectionHelper takes care of + * booleans in set* methods so we can assume that the right + * value (boolean primitive) is coming in here. + * + * @param boolean Preserve the timestamp on the destination file + * @return void + * @access public + */ + function setTstamp($bool) { + $this->preserveLMT = (boolean) $bool; + } + + + /** + * Set the include empty dirs flag. IntrospectionHelper takes care of + * booleans in set* methods so we can assume that the right + * value (boolean primitive) is coming in here. + * + * @param boolean Flag if empty dirs should be cpoied too + * @return void + * @access public + */ + function setIncludeEmptyDirs($bool) { + $this->includeEmpty = (boolean) $bool; + } + + + /** + * Set the file. We have to manually take care of the + * type that is coming due to limited type support in php + * in and convert it manually if neccessary. + * + * @param string/object The source file. Either a string or an PhingFile object + * @return void + * @access public + */ + function setFile(PhingFile $file) { + $this->file = $file; + } + + + /** + * Set the toFile. We have to manually take care of the + * type that is coming due to limited type support in php + * in and convert it manually if neccessary. + * + * @param string/object The dest file. Either a string or an PhingFile object + * @return void + * @access public + */ + function setTofile(PhingFile $file) { + $this->destFile = $file; + } + + + /** + * Set the toDir. We have to manually take care of the + * type that is coming due to limited type support in php + * in and convert it manually if neccessary. + * + * @param string/object The directory, either a string or an PhingFile object + * @return void + * @access public + */ + function setTodir(PhingFile $dir) { + $this->destDir = $dir; + } + + /** + * Nested creator, creates a FileSet for this task + * + * @access public + * @return object The created fileset object + */ + function createFileSet() { + $num = array_push($this->filesets, new FileSet()); + return $this->filesets[$num-1]; + } + + /** + * Creates a filterchain + * + * @access public + * @return object The created filterchain object + */ + function createFilterChain() { + $num = array_push($this->filterChains, new FilterChain($this->project)); + return $this->filterChains[$num-1]; + } + + /** + * Nested creator, creates one Mapper for this task + * + * @access public + * @return object The created Mapper type object + * @throws BuildException + */ + function createMapper() { + if ($this->mapperElement !== null) { + throw new BuildException("Cannot define more than one mapper", $this->location); + } + $this->mapperElement = new Mapper($this->project); + return $this->mapperElement; + } + + /** + * The main entry point where everything gets in motion. + * + * @access public + * @return true on success + * @throws BuildException + */ + function main() { + + $this->validateAttributes(); + + if ($this->file !== null) { + if ($this->file->exists()) { + if ($this->destFile === null) { + $this->destFile = new PhingFile($this->destDir, (string) $this->file->getName()); + } + if ($this->overwrite === true || ($this->file->lastModified() > $this->destFile->lastModified())) { + $this->fileCopyMap[$this->file->getAbsolutePath()] = $this->destFile->getAbsolutePath(); + } else { + $this->log($this->file->getName()." omitted, is up to date"); + } + } else { + // terminate build + throw new BuildException("Could not find file " . $this->file->__toString() . " to copy."); + } + } + + $project = $this->getProject(); + + // process filesets + foreach($this->filesets as $fs) { + $ds = $fs->getDirectoryScanner($project); + $fromDir = $fs->getDir($project); + $srcFiles = $ds->getIncludedFiles(); + $srcDirs = $ds->getIncludedDirectories(); + $this->_scan($fromDir, $this->destDir, $srcFiles, $srcDirs); + } + + // go and copy the stuff + $this->doWork(); + + if ($this->destFile !== null) { + $this->destDir = null; + } + } + + /** + * Validates attributes coming in from XML + * + * @access private + * @return void + * @throws BuildException + */ + private function validateAttributes() { + + if ($this->file === null && count($this->filesets) === 0) { + throw new BuildException("CopyTask. Specify at least one source - a file or a fileset."); + } + + if ($this->destFile !== null && $this->destDir !== null) { + throw new BuildException("Only one of destfile and destdir may be set."); + } + + if ($this->destFile === null && $this->destDir === null) { + throw new BuildException("One of destfile or destdir must be set."); + } + + if ($this->file !== null && $this->file->exists() && $this->file->isDirectory()) { + throw new BuildException("Use a fileset to copy directories."); + } + + if ($this->destFile !== null && count($this->filesets) > 0) { + throw new BuildException("Cannot concatenate multple files into a single file."); + } + + if ($this->destFile !== null) { + $this->destDir = new PhingFile($this->destFile->getParent()); + } + } + + /** + * Compares source files to destination files to see if they + * should be copied. + * + * @access private + * @return void + */ + private function _scan(&$fromDir, &$toDir, &$files, &$dirs) { + /* mappers should be generic, so we get the mappers here and + pass them on to builMap. This method is not redundan like it seems */ + $mapper = null; + if ($this->mapperElement !== null) { + $mapper = $this->mapperElement->getImplementation(); + } else if ($this->flatten) { + $mapper = new FlattenMapper(); + } else { + $mapper = new IdentityMapper(); + } + $this->buildMap($fromDir, $toDir, $files, $mapper, $this->fileCopyMap); + $this->buildMap($fromDir, $toDir, $dirs, $mapper, $this->dirCopyMap); + } + + /** + * Builds a map of filenames (from->to) that should be copied + * + * @access private + * @return void + */ + private function buildMap(&$fromDir, &$toDir, &$names, &$mapper, &$map) { + $toCopy = null; + if ($this->overwrite) { + $v = array(); + foreach($names as $name) { + $result = $mapper->main($name); + if ($result !== null) { + $v[] = $name; + } + } + $toCopy = $v; + } else { + $ds = new SourceFileScanner($this); + $toCopy = $ds->restrict($names, $fromDir, $toDir, $mapper); + } + + for ($i=0,$_i=count($toCopy); $i < $_i; $i++) { + $src = new PhingFile($fromDir, $toCopy[$i]); + $mapped = $mapper->main($toCopy[$i]); + $dest = new PhingFile($toDir, $mapped[0]); + $map[$src->getAbsolutePath()] = $dest->getAbsolutePath(); + } + } + + + /** + * Actually copies the files + * + * @access private + * @return void + * @throws BuildException + */ + private function doWork() { + + // These "slots" allow filters to retrieve information about the currently-being-process files + $fromSlot = $this->getRegisterSlot("currentFromFile"); + $fromBasenameSlot = $this->getRegisterSlot("currentFromFile.basename"); + + $toSlot = $this->getRegisterSlot("currentToFile"); + $toBasenameSlot = $this->getRegisterSlot("currentToFile.basename"); + + $mapSize = count($this->fileCopyMap); + $total = $mapSize; + if ($mapSize > 0) { + $this->log("Copying ".$mapSize." file".(($mapSize) === 1 ? '' : 's')." to ". $this->destDir->getAbsolutePath()); + // walks the map and actually copies the files + $count=0; + foreach($this->fileCopyMap as $from => $to) { + if ($from === $to) { + $this->log("Skipping self-copy of " . $from, $this->verbosity); + $total--; + continue; + } + $this->log("From ".$from." to ".$to, $this->verbosity); + try { // try to copy file + + $fromFile = new PhingFile($from); + $toFile = new PhingFile($to); + + $fromSlot->setValue($fromFile->getPath()); + $fromBasenameSlot->setValue($fromFile->getName()); + + $toSlot->setValue($toFile->getPath()); + $toBasenameSlot->setValue($toFile->getName()); + + $this->fileUtils->copyFile($fromFile, $toFile, $this->overwrite, $this->preserveLMT, $this->filterChains, $this->getProject()); + + $count++; + } catch (IOException $ioe) { + $this->log("Failed to copy " . $from . " to " . $to . ": " . $ioe->getMessage(), PROJECT_MSG_ERR); + } + } + } + + // handle empty dirs if appropriate + if ($this->includeEmpty) { + $e = array_values($this->dirCopyMap); + $count = 0; + foreach ($e as $dir) { + $d = new PhingFile((string) $dir); + if (!$d->exists()) { + if (!$d->mkdirs()) { + $this->log("Unable to create directory " . $d->__toString(), PROJECT_MSG_ERR); + } else { + $count++; + } + } + } + if ($count > 0) { + $this->log("Copied ".$count." empty director" . ($count == 1 ? "y" : "ies") . " to " . $this->destDir->getAbsolutePath()); + } + } + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/CvsPassTask.php b/buildscripts/phing/classes/phing/tasks/system/CvsPassTask.php new file mode 100644 index 00000000..0003c50f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/CvsPassTask.php @@ -0,0 +1,173 @@ +. + */ + +require_once 'phing/Task.php'; +include_once 'phing/system/io/BufferedReader.php'; +include_once 'phing/system/io/BufferedWriter.php'; +include_once 'phing/util/StringHelper.php'; + +/** + * Adds an new entry to a CVS password file. + * + * @author Hans Lellelid (Phing) + * @author Jeff Martin (Ant) + * @version $Revision: 1.7 $ + * @package phing.tasks.system + */ +class CVSPassTask extends Task { + + /** CVS Root */ + private $cvsRoot; + /** Password file to add password to */ + private $passFile; + /** Password to add to file */ + private $password; + + /** Array contain char conversion data */ + private static $shifts = array( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 114, 120, 53, 79, 96, 109, 72, 108, 70, 64, 76, 67, 116, 74, 68, 87, + 111, 52, 75, 119, 49, 34, 82, 81, 95, 65, 112, 86, 118, 110, 122, 105, + 41, 57, 83, 43, 46, 102, 40, 89, 38, 103, 45, 50, 42, 123, 91, 35, + 125, 55, 54, 66, 124, 126, 59, 47, 92, 71, 115, 78, 88, 107, 106, 56, + 36, 121, 117, 104, 101, 100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48, + 58, 113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85, 223, + 225, 216, 187, 166, 229, 189, 222, 188, 141, 249, 148, 200, 184, 136, 248, 190, + 199, 170, 181, 204, 138, 232, 218, 183, 255, 234, 220, 247, 213, 203, 226, 193, + 174, 172, 228, 252, 217, 201, 131, 230, 197, 211, 145, 238, 161, 179, 160, 212, + 207, 221, 254, 173, 202, 146, 224, 151, 140, 196, 205, 130, 135, 133, 143, 246, + 192, 159, 244, 239, 185, 168, 215, 144, 139, 165, 180, 157, 147, 186, 214, 176, + 227, 231, 219, 169, 175, 156, 206, 198, 129, 164, 150, 210, 154, 177, 134, 127, + 182, 128, 158, 208, 162, 132, 167, 209, 149, 241, 153, 251, 237, 236, 171, 195, + 243, 233, 253, 240, 194, 250, 191, 155, 142, 137, 245, 235, 163, 242, 178, 152 + ); + + /** + * Create a CVS task using the default cvspass file location. + */ + public function __construct() { + $this->passFile = new PhingFile( + Phing::getProperty("cygwin.user.home", + Phing::getProperty("user.home")) + . DIRECTORY_SEPARATOR . ".cvspass"); + } + + /** + * Does the work. + * + * @throws BuildException if someting goes wrong with the build + */ + public final function main() { + if ($this->cvsRoot === null) { + throw new BuildException("cvsroot is required"); + } + if ($this->password === null) { + throw new BuildException("password is required"); + } + + $this->log("cvsRoot: " . $this->cvsRoot, PROJECT_MSG_DEBUG); + $this->log("password: " . $this->password, PROJECT_MSG_DEBUG); + $this->log("passFile: " . $this->passFile->__toString(), PROJECT_MSG_DEBUG); + + $reader = null; + $writer = null; + + try { + $buf = ""; + + if ($this->passFile->exists()) { + $reader = new BufferedReader(new FileReader($this->passFile)); + + $line = null; + while (($line = $reader->readLine()) !== null) { + if (!StringHelper::startsWith($this->cvsRoot, $line)) { + $buf .= $line . Phing::getProperty("line.separator"); + } + } + } + + $pwdfile = $buf . $this->cvsRoot . " A" . $this->mangle($this->password); + + $this->log("Writing -> " . $pwdfile , PROJECT_MSG_DEBUG); + + $writer = new BufferedWriter(new FileWriter($this->passFile)); + $writer->write($pwdfile); + $writer->newLine(); + + $writer->close(); + if ($reader) { + $reader->close(); + } + + } catch (IOException $e) { + if ($reader) { + try { + $reader->close(); + } catch (Exception $e) {} + } + + if ($writer) { + try { + $writer->close(); + } catch (Exception $e) {} + } + + throw new BuildException($e); + } + } + + /** + * "Encode" the password. + */ + private final function mangle($password){ + $buf = ""; + for ($i = 0, $plen = strlen($password); $i < $plen; $i++) { + $buf .= chr(self::$shifts[ord($password{$i})]); + } + return $buf; + } + + /** + * The CVS repository to add an entry for. + * @param string $cvsRoot + */ + public function setCvsroot($cvsRoot) { + $this->cvsRoot = $cvsRoot; + } + + /** + * Password file to add the entry to. + * @param PhingFile $passFile + */ + public function setPassfile(PhingFile $passFile) { + $this->passFile = $passFile; + } + + /** + * Password to be added to the password file. + * @param string $password + */ + public function setPassword($password) { + $this->password = $password; + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/CvsTask.php b/buildscripts/phing/classes/phing/tasks/system/CvsTask.php new file mode 100644 index 00000000..de2950ec --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/CvsTask.php @@ -0,0 +1,540 @@ +. + */ + +require_once 'phing/Task.php'; +include_once 'phing/tasks/system/ExecTask.php'; +include_once 'phing/types/Commandline.php'; + +/** + * Task for performing CVS operations. + * + * NOTE: This implementation has been moved here from Cvs.java with + * the addition of some accessors for extensibility. Another task + * can extend this with some customized output processing. + * + * @author Hans Lellelid (Phing) + * @author costin@dnt.ro (Ant) + * @author stefano@apache.org (Ant) + * @author Wolfgang Werner (Ant) + * @author Kevin Ross (Ant) + * @version $Revision: 1.14 $ + * @package phing.tasks.system + */ +class CvsTask extends Task { + + /** + * Default compression level to use, if compression is enabled via + * setCompression( true ). + */ + const DEFAULT_COMPRESSION_LEVEL = 3; + + private $cmd; + + /** + * List of Commandline children + * @var array Commandline[] + */ + private $commandlines = array(); + + /** + * the CVSROOT variable. + */ + private $cvsRoot; + + /** + * the CVS_RSH variable. + */ + private $cvsRsh; + + /** + * the package/module to check out. + */ + private $cvsModule; + + /** + * the default command. + */ + private static $default_command = "checkout"; + + /** + * the CVS command to execute. + */ + private $command = null; + + /** + * suppress information messages. + */ + private $quiet = false; + + /** + * compression level to use. + */ + private $compression = 0; + + /** + * report only, don't change any files. + */ + private $noexec = false; + + /** + * CVS port + */ + private $port = 0; + + /** + * CVS password file + * @var File + */ + private $passFile = null; + + /** + * the directory where the checked out files should be placed. + * @var File + */ + private $dest; + + private $error; + + private $output; + + /** + * If true it will stop the build if cvs exits with error. + * Default is false. (Iulian) + * @var boolean + */ + private $failOnError = false; + + public function init() { + $this->cmd = new Commandline(); + } + + /** + * Sets up the environment for toExecute and then runs it. + * @param Commandline $toExecute + * @throws BuildException + */ + protected function runCommand(Commandline $toExecute) { + + // We are putting variables into the script's environment + // and not removing them (!) This should be fine, but is + // worth remembering and testing. + + if ($this->port > 0) { + putenv("CVS_CLIENT_PORT=".$this->port); + } + + // Need a better cross platform integration with , so + // use the same filename. + + if ($this->passFile === null) { + $defaultPassFile = new PhingFile(Phing::getProperty("cygwin.user.home", Phing::getProperty("user.home")) + . DIRECTORY_SEPARATOR . ".cvspass"); + if($defaultPassFile->exists()) { + $this->setPassfile($defaultPassFile); + } + } + + if ($this->passFile !== null) { + if ($this->passFile->isFile() && $this->passFile->canRead()) { + putenv("CVS_PASSFILE=" . $this->passFile->__toString()); + $this->log("Using cvs passfile: " . $this->passFile->__toString(), PROJECT_MSG_INFO); + } elseif (!$this->passFile->canRead()) { + $this->log("cvs passfile: " . $this->passFile->__toString() + . " ignored as it is not readable", PROJECT_MSG_WARN); + } else { + $this->log("cvs passfile: " . $this->passFile->__toString() + . " ignored as it is not a file", + PROJECT_MSG_WARN); + } + } + + if ($this->cvsRsh !== null) { + putenv("CVS_RSH=".$this->cvsRsh); + } + + // Use the ExecTask to handle execution of the command + $exe = new ExecTask($this->project); + $exe->setProject($this->project); + + //exe.setAntRun(project); + if ($this->dest === null) { + $this->dest = $this->project->getBaseDir(); + } + + if (!$this->dest->exists()) { + $this->dest->mkdirs(); + } + + if ($this->output !== null) { + $exe->setOutput($this->output); + } + + if ($this->error !== null) { + $exe->setError($this->error); + } + + $exe->setDir($this->dest); + + if (is_object($toExecute)) { + $toExecuteStr = $toExecute->__toString(); // unfortunately no more automagic for initial 5.0.0 release :( + } + + $exe->setCommand($toExecuteStr); + + try { + $actualCommandLine = $toExecuteStr; // we converted to string above + $this->log($actualCommandLine, PROJECT_MSG_INFO); + $retCode = $exe->execute(); + $this->log("retCode=" . $retCode, PROJECT_MSG_DEBUG); + /*Throw an exception if cvs exited with error. (Iulian)*/ + if ($this->failOnError && $retCode !== 0) { + throw new BuildException("cvs exited with error code " + . $retCode + . Phing::getProperty("line.separator") + . "Command line was [" + . $toExecute->describeCommand() . "]", $this->getLocation()); + } + } catch (IOException $e) { + if ($this->failOnError) { + throw new BuildException($e, $this->getLocation()); + } else { + $this->log("Caught exception: " . $e, PROJECT_MSG_WARN); + } + } catch (BuildException $e) { + if ($this->failOnError) { + throw $e; + } else { + $t = $e->getCause(); + if ($t === null) { + $t = $e; + } + $this->log("Caught exception: " . $t, PROJECT_MSG_WARN); + } + } catch (Exception $e) { + if ($this->failOnError) { + throw new BuildException($e, $this->getLocation()); + } else { + $this->log("Caught exception: " . $e, PROJECT_MSG_WARN); + } + } + } + + /** + * + * @return void + * @throws BuildException + */ + public function main() { + + $savedCommand = $this->getCommand(); + + if ($this->getCommand() === null && empty($this->commandlines)) { + // re-implement legacy behaviour: + $this->setCommand(self::$default_command); + } + + $c = $this->getCommand(); + $cloned = null; + if ($c !== null) { + $cloned = $this->cmd->__copy(); + $cloned->createArgument(true)->setLine($c); + $this->addConfiguredCommandline($cloned, true); + } + + try { + for ($i = 0, $vecsize=count($this->commandlines); $i < $vecsize; $i++) { + $this->runCommand($this->commandlines[$i]); + } + + // finally { + if ($cloned !== null) { + $this->removeCommandline($cloned); + } + $this->setCommand($savedCommand); + + } catch (Exception $e) { + // finally { + if ($cloned !== null) { + $this->removeCommandline($cloned); + } + $this->setCommand($savedCommand); + throw $e; + } + } + + /** + * The CVSROOT variable. + * + * @param string $root + */ + public function setCvsRoot($root) { + + // Check if not real cvsroot => set it to null + if ($root !== null) { + if (trim($root) == "") { + $root = null; + } + } + + $this->cvsRoot = $root; + } + + public function getCvsRoot() { + return $this->cvsRoot; + } + + /** + * The CVS_RSH variable. + * + * @param rsh + */ + public function setCvsRsh($rsh) { + // Check if not real cvsrsh => set it to null + if ($rsh !== null) { + if (trim($rsh) == "") { + $rsh = null; + } + } + + $this->cvsRsh = $rsh; + } + + public function getCvsRsh() { + return $this->cvsRsh; + } + + /** + * Port used by CVS to communicate with the server. + * + * @param int $port + */ + public function setPort($port){ + $this->port = $port; + } + + /** + * @return int + */ + public function getPort() { + return $this->port; + } + + /** + * Password file to read passwords from. + * + * @param passFile + */ + public function setPassfile(PhingFile $passFile) { + $this->passFile = $passFile; + } + + /** + * @return File + */ + public function getPassFile() { + return $this->passFile; + } + + /** + * The directory where the checked out files should be placed. + * + * @param PhingFile $dest + */ + public function setDest(PhingFile $dest) { + $this->dest = $dest; + } + + public function getDest() { + return $this->dest; + } + + /** + * The package/module to operate upon. + * + * @param string $p + */ + public function setModule($m) { + $this->cvsModule = $m; + } + + public function getModule(){ + return $this->cvsModule; + } + + /** + * The tag of the package/module to operate upon. + * @param string $p + */ + public function setTag($p) { + // Check if not real tag => set it to null + if ($p !== null && trim($p) !== "") { + $this->appendCommandArgument("-r"); + $this->appendCommandArgument($p); + } + } + + /** + * This needs to be public to allow configuration + * of commands externally. + */ + public function appendCommandArgument($arg) { + $this->cmd->createArgument()->setValue($arg); + } + + /** + * Use the most recent revision no later than the given date. + * @param p + */ + public function setDate($p) { + if ($p !== null && trim($p) !== "") { + $this->appendCommandArgument("-D"); + $this->appendCommandArgument($p); + } + } + + /** + * The CVS command to execute. + * @param string $c + */ + public function setCommand($c) { + $this->command = $c; + } + + public function getCommand() { + return $this->command; + } + + /** + * If true, suppress informational messages. + * @param boolean $q + */ + public function setQuiet($q) { + $this->quiet = $q; + } + + /** + * If true, report only and don't change any files. + * + * @param boolean $ne + */ + public function setNoexec($ne) { + $this->noexec = (boolean) $ne; + } + + /** + * Stop the build process if the command exits with + * a return code other than 0. + * Defaults to false. + * @param boolean $failOnError + */ + public function setFailOnError($failOnError) { + $this->failOnError = (boolean) $failOnError; + } + + /** + * Configure a commandline element for things like cvsRoot, quiet, etc. + * @return string + */ + protected function configureCommandline($c) { + if ($c === null) { + return; + } + $c->setExecutable("cvs"); + + if ($this->cvsModule !== null) { + $c->createArgument()->setLine($this->cvsModule); + } + if ($this->compression > 0 && $this->compression < 10) { + $c->createArgument(true)->setValue("-z" . $this->compression); + } + if ($this->quiet) { + $c->createArgument(true)->setValue("-q"); + } + if ($this->noexec) { + $c->createArgument(true)->setValue("-n"); + } + if ($this->cvsRoot !== null) { + $c->createArgument(true)->setLine("-d" . $this->cvsRoot); + } + } + + protected function removeCommandline(Commandline $c) { + $idx = array_search($c, $this->commandlines, true); + if ($idx === false) { + return false; + } + $this->commandlines = array_splice($this->commandlines, $idx, 1); + return true; + } + + /** + * Configures and adds the given Commandline. + * @param insertAtStart If true, c is + */ + public function addConfiguredCommandline(Commandline $c, $insertAtStart = false) { + if ($c === null) { + return; + } + $this->configureCommandline($c); + if ($insertAtStart) { + array_unshift($this->commandlines, $c); + } else { + array_push($this->commandlines, $c); + } + } + + /** + * If set to a value 1-9 it adds -zN to the cvs command line, else + * it disables compression. + * @param int $level + */ + public function setCompressionLevel($level) { + $this->compression = $level; + } + + /** + * If true, this is the same as compressionlevel="3". + * + * @param boolean $usecomp If true, turns on compression using default + * level, AbstractCvsTask.DEFAULT_COMPRESSION_LEVEL. + */ + public function setCompression($usecomp) { + $this->setCompressionLevel($usecomp ? + self::DEFAULT_COMPRESSION_LEVEL : 0); + } + + /** + * File to which output should be written. + * @param PhingFile $output + */ + function setOutput(PhingFile $f) { + $this->output = $f; + } + + /** + * File to which error output should be written. + * @param PhingFile $output + */ + function setError(PhingFile $f) { + $this->error = $f; + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/DeleteTask.php b/buildscripts/phing/classes/phing/tasks/system/DeleteTask.php new file mode 100644 index 00000000..00e1e7a7 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/DeleteTask.php @@ -0,0 +1,277 @@ +. + */ + +require_once 'phing/Task.php'; + +/** + * Deletes a file or directory, or set of files defined by a fileset. + * + * @version $Revision: 1.13 $ + * @package phing.tasks.system + */ +class DeleteTask extends Task { + + protected $file; + protected $dir; + protected $filesets = array(); + protected $includeEmpty = false; + + protected $quiet = false; + protected $failonerror = true; + protected $verbosity = PROJECT_MSG_VERBOSE; + + /** Any filelists of files that should be deleted. */ + private $filelists = array(); + + /** + * Set the name of a single file to be removed. + * @param PhingFile $file + */ + function setFile(PhingFile $file) { + $this->file = $file; + } + + /** + * Set the directory from which files are to be deleted. + * @param PhingFile $dir + */ + function setDir(PhingFile $dir) { + $this->dir = $dir; + } + + /** + * Used to force listing of all names of deleted files. + * @param boolean $verbosity + */ + function setVerbose($verbosity) { + if ($verbosity) { + $this->verbosity = PROJECT_MSG_INFO; + } else { + $this->verbosity = PROJECT_MSG_VERBOSE; + } + } + + /** + * If the file does not exist, do not display a diagnostic + * message or modify the exit status to reflect an error. + * This means that if a file or directory cannot be deleted, + * then no error is reported. This setting emulates the + * -f option to the Unix rm command. Default is false + * meaning things are verbose + */ + function setQuiet($bool) { + $this->quiet = $bool; + if ($this->quiet) { + $this->failonerror = false; + } + } + + /** this flag means 'note errors to the output, but keep going' */ + function setFailOnError($bool) { + $this->failonerror = $bool; + } + + + /** Used to delete empty directories.*/ + function setIncludeEmptyDirs($includeEmpty) { + $this->includeEmpty = (boolean) $includeEmpty; + } + + /** Nested creator, adds a set of files (nested fileset attribute). */ + function createFileSet() { + $num = array_push($this->filesets, new FileSet()); + return $this->filesets[$num-1]; + } + + /** Nested creator, adds a set of files (nested fileset attribute). */ + function createFileList() { + $num = array_push($this->filelists, new FileList()); + return $this->filelists[$num-1]; + } + + /** Delete the file(s). */ + function main() { + if ($this->file === null && $this->dir === null && count($this->filesets) === 0 && count($this->filelists) === 0) { + throw new BuildException("At least one of the file or dir attributes, or a fileset element, or a filelist element must be set."); + } + + if ($this->quiet && $this->failonerror) { + throw new BuildException("quiet and failonerror cannot both be set to true", $this->location); + } + + // delete a single file + if ($this->file !== null) { + if ($this->file->exists()) { + if ($this->file->isDirectory()) { + $this->log("Directory " . $this->file->__toString() . " cannot be removed using the file attribute. Use dir instead."); + } else { + $this->log("Deleting: " . $this->file->__toString()); + try { + $this->file->delete(); + } catch(Exception $e) { + $message = "Unable to delete file " . $this->file->__toString() .": " .$e->getMessage(); + if($this->failonerror) { + throw new BuildException($message); + } else { + $this->log($message, $this->quiet ? PROJECT_MSG_VERBOSE : PROJECT_MSG_WARN); + } + } + } + } else { + $this->log("Could not find file " . $this->file->getAbsolutePath() . " to delete.",PROJECT_MSG_VERBOSE); + } + } + + // delete the directory + if ($this->dir !== null && $this->dir->exists() && $this->dir->isDirectory()) { + if ($this->verbosity === PROJECT_MSG_VERBOSE) { + $this->log("Deleting directory " . $this->dir->__toString()); + } + $this->removeDir($this->dir); + } + + // delete the files in the filelists + foreach($this->filelists as $fl) { + try { + $files = $fl->getFiles($this->project); + $this->removeFiles($fl->getDir($this->project), $files, $empty=array()); + } catch (BuildException $be) { + // directory doesn't exist or is not readable + if ($this->failonerror) { + throw $be; + } else { + $this->log($be->getMessage(), $this->quiet ? PROJECT_MSG_VERBOSE : PROJECT_MSG_WARN); + } + } + } + + // delete the files in the filesets + foreach($this->filesets as $fs) { + try { + $ds = $fs->getDirectoryScanner($this->project); + $files = $ds->getIncludedFiles(); + $dirs = $ds->getIncludedDirectories(); + $this->removeFiles($fs->getDir($this->project), $files, $dirs); + } catch (BuildException $be) { + // directory doesn't exist or is not readable + if ($this->failonerror) { + throw $be; + } else { + $this->log($be->getMessage(), $this->quiet ? PROJECT_MSG_VERBOSE : PROJECT_MSG_WARN); + } + } + } + } + + /** + * Recursively removes a directory. + * @param PhingFile $d The directory to remove. + */ + private function removeDir($d) { + $list = $d->listDir(); + if ($list === null) { + $list = array(); + } + + foreach($list as $s) { + $f = new PhingFile($d, $s); + if ($f->isDirectory()) { + $this->removeDir($f); + } else { + $this->log("Deleting " . $f->__toString(), $this->verbosity); + try { + $f->delete(); + } catch (Exception $e) { + $message = "Unable to delete file " . $f->__toString() . ": " . $e->getMessage(); + if($this->failonerror) { + throw new BuildException($message); + } else { + $this->log($message, $this->quiet ? PROJECT_MSG_VERBOSE : PROJECT_MSG_WARN); + } + } + } + } + $this->log("Deleting directory " . $d->getAbsolutePath(), $this->verbosity); + try { + $d->delete(); + } catch (Exception $e) { + $message = "Unable to delete directory " . $d->__toString() . ": " . $e->getMessage(); + if($this->failonerror) { + throw new BuildException($message); + } else { + $this->log($message, $this->quiet ? PROJECT_MSG_VERBOSE : PROJECT_MSG_WARN); + } + } + } + + /** + * remove an array of files in a directory, and a list of subdirectories + * which will only be deleted if 'includeEmpty' is true + * @param PhingFile $d directory to work from + * @param array &$files array of files to delete; can be of zero length + * @param array &$dirs array of directories to delete; can of zero length + */ + private function removeFiles(PhingFile $d, &$files, &$dirs) { + if (count($files) > 0) { + $this->log("Deleting " . count($files) . " files from " . $d->__toString()); + for ($j=0,$_j=count($files); $j < $_j; $j++) { + $f = new PhingFile($d, $files[$j]); + $this->log("Deleting " . $f->getAbsolutePath(), $this->verbosity); + try { + $f->delete(); + } catch (Exception $e) { + $message = "Unable to delete file " . $f->__toString() . ": " . $e->getMessage(); + if($this->failonerror) { + throw new BuildException($message); + } else { + $this->log($message, $this->quiet ? PROJECT_MSG_VERBOSE : PROJECT_MSG_WARN); + } + } + + } + } + + if (count($dirs) > 0 && $this->includeEmpty) { + $dirCount = 0; + for ($j=count($dirs)-1; $j>=0; --$j) { + $dir = new PhingFile($d, $dirs[$j]); + $dirFiles = $dir->listDir(); + if ($dirFiles === null || count($dirFiles) === 0) { + $this->log("Deleting " . $dir->__toString(), $this->verbosity); + try { + $dir->delete(); + $dirCount++; + } catch (Exception $e) { + $message="Unable to delete directory " + $dir; + if($this->failonerror) { + throw new BuildException($message); + } else { + $this->log($message, $this->quiet ? PROJECT_MSG_VERBOSE : PROJECT_MSG_WARN); + } + } + } + } + if ($dirCount > 0) { + $this->log("Deleted $dirCount director" . ($dirCount==1 ? "y" : "ies") . " from " . $d->__toString()); + } + } + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/EchoTask.php b/buildscripts/phing/classes/phing/tasks/system/EchoTask.php new file mode 100644 index 00000000..229f5130 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/EchoTask.php @@ -0,0 +1,107 @@ +. + */ + +include_once 'phing/Task.php'; + +/** + * Echos a message to the logging system or to a file + * + * @author Michiel Rook + * @author Andreas Aderhold, andi@binarycloud.com + * @version $Revision: 1.5 $ $Date: 2006-04-28 10:49:47 -0400 (Fri, 28 Apr 2006) $ + * @package phing.tasks.system + */ + +class EchoTask extends Task { + + protected $msg = ""; + + protected $file = ""; + + protected $append = false; + + protected $level = "info"; + + function main() { + switch ($this->level) + { + case "error": $loglevel = PROJECT_MSG_ERR; break; + case "warning": $loglevel = PROJECT_MSG_WARN; break; + case "info": $loglevel = PROJECT_MSG_INFO; break; + case "verbose": $loglevel = PROJECT_MSG_VERBOSE; break; + case "debug": $loglevel = PROJECT_MSG_DEBUG; break; + } + + if (empty($this->file)) + { + $this->log($this->msg, $loglevel); + } + else + { + if ($this->append) + { + $handle = fopen($this->file, "a"); + } + else + { + $handle = fopen($this->file, "w"); + } + + fwrite($handle, $this->msg); + + fclose($handle); + } + } + + /** setter for file */ + function setFile($file) + { + $this->file = (string) $file; + } + + /** setter for level */ + function setLevel($level) + { + $this->level = (string) $level; + } + + /** setter for append */ + function setAppend($append) + { + $this->append = $append; + } + + /** setter for message */ + function setMsg($msg) { + $this->setMessage($msg); + } + + /** alias setter */ + function setMessage($msg) { + $this->msg = (string) $msg; + } + + /** Supporting the Message syntax. */ + function addText($msg) + { + $this->msg = (string) $msg; + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/ExecTask.php b/buildscripts/phing/classes/phing/tasks/system/ExecTask.php new file mode 100644 index 00000000..104f7697 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/ExecTask.php @@ -0,0 +1,248 @@ +. + */ + +require_once 'phing/Task.php'; + +/** + * Executes a command on the shell. + * + * @author Andreas Aderhold + * @author Hans Lellelid + * @version $Revision: 1.17 $ + * @package phing.tasks.system + */ +class ExecTask extends Task { + + /** + * Command to execute. + * @var string + */ + protected $command; + + /** + * Working directory. + * @var File + */ + protected $dir; + + /** + * Operating system. + * @var string + */ + protected $os; + + /** + * Whether to escape shell command using escapeshellcmd(). + * @var boolean + */ + protected $escape = false; + + /** + * Where to direct output. + * @var File + */ + protected $output; + + /** + * Whether to passthru the output + * @var boolean + */ + protected $passthru = false; + + /** + * Where to direct error output. + * @var File + */ + protected $error; + + /** + * If spawn is set then [unix] programs will redirect stdout and add '&'. + * @var boolean + */ + protected $spawn = false; + + /** + * Whether to check the return code. + * @var boolean + */ + protected $checkreturn = false; + + /** + * Main method: wraps execute() command. + * @return void + */ + public function main() { + $this->execute(); + } + + /** + * Executes a program and returns the return code. + * Output from command is logged at INFO level. + * @return int Return code from execution. + */ + public function execute() { + + // test if os match + $myos = Phing::getProperty("os.name"); + $this->log("Myos = " . $myos, PROJECT_MSG_VERBOSE); + if (($this->os !== null) && (strpos($os, $myos) === false)) { + // this command will be executed only on the specified OS + $this->log("Not found in " . $os, PROJECT_MSG_VERBOSE); + return 0; + } + + if ($this->dir !== null) { + if ($this->dir->isDirectory()) { + $currdir = getcwd(); + @chdir($this->dir->getPath()); + } else { + throw new BuildException("Can't chdir to:" . $this->dir->__toString()); + } + } + + + if ($this->escape == true) { + // FIXME - figure out whether this is correct behavior + $this->command = escapeshellcmd($this->command); + } + + if ($this->error !== null) { + $this->command .= ' 2> ' . $this->error->getPath(); + $this->log("Writing error output to: " . $this->error->getPath()); + } + + if ($this->output !== null) { + $this->command .= ' 1> ' . $this->output->getPath(); + $this->log("Writing standard output to: " . $this->output->getPath()); + } elseif ($this->spawn) { + $this->command .= ' 1>/dev/null'; + $this->log("Sending ouptut to /dev/null"); + } + + // If neither output nor error are being written to file + // then we'll redirect error to stdout so that we can dump + // it to screen below. + + if ($this->output === null && $this->error === null) { + $this->command .= ' 2>&1'; + } + + // we ignore the spawn boolean for windows + if ($this->spawn) { + $this->command .= ' &'; + } + + $this->log("Executing command: " . $this->command); + + $output = array(); + $return = null; + exec($this->command, $output, $return); + + if ($this->dir !== null) { + @chdir($currdir); + } + + foreach($output as $line) { + $this->log($line, ($this->passthru ? PROJECT_MSG_INFO : PROJECT_MSG_VERBOSE)); + } + + if($return != 0 && $this->checkreturn) + { + throw new BuildException("Task exited with code $return"); + } + + return $return; + } + + /** + * The command to use. + * @param mixed $command String or string-compatible (e.g. w/ __toString()). + */ + function setCommand($command) { + $this->command = "" . $command; + } + + /** + * Whether to use escapeshellcmd() to escape command. + * @param boolean $escape + */ + function setEscape($escape) { + $this->escape = (bool) $escape; + } + + /** + * Specify the workign directory for executing this command. + * @param PhingFile $dir + */ + function setDir(PhingFile $dir) { + $this->dir = $dir; + } + + /** + * Specify OS (or muliple OS) that must match in order to execute this command. + * @param string $os + */ + function setOs($os) { + $this->os = (string) $os; + } + + /** + * File to which output should be written. + * @param PhingFile $output + */ + function setOutput(PhingFile $f) { + $this->output = $f; + } + + /** + * File to which error output should be written. + * @param PhingFile $output + */ + function setError(PhingFile $f) { + $this->error = $f; + } + + /** + * Whether to use passthru the output. + * @param boolean $passthru + */ + function setPassthru($passthru) { + $this->passthru = (bool) $passthru; + } + + /** + * Whether to suppress all output and run in the background. + * @param boolean $spawn + */ + function setSpawn($spawn) { + $this->spawn = (bool) $spawn; + } + + /** + * Whether to check the return code. + * @param boolean $checkreturn + */ + function setCheckreturn($checkreturn) { + $this->checkreturn = (bool) $checkreturn; + } +} + diff --git a/buildscripts/phing/classes/phing/tasks/system/ExitTask.php b/buildscripts/phing/classes/phing/tasks/system/ExitTask.php new file mode 100644 index 00000000..7e08d369 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/ExitTask.php @@ -0,0 +1,118 @@ +. + */ + +require_once 'phing/Task.php'; + +/** + * Exits the active build, giving an additional message + * if available. + * + * @author Hans Lellelid (Phing) + * @author Nico Seessle (Ant) + * @version $Revision: 1.7 $ + * @package phing.tasks.system + */ +class ExitTask extends Task { + + private $message; + private $ifCondition; + private $unlessCondition; + + /** + * A message giving further information on why the build exited. + * + * @param string $value message to output + */ + public function setMsg($value) { + $this->setMessage($value); + } + + /** + * A message giving further information on why the build exited. + * + * @param value message to output + */ + public function setMessage($value) { + $this->message = $value; + } + + /** + * Only fail if a property of the given name exists in the current project. + * @param c property name + */ + public function setIf($c) { + $this->ifCondition = $c; + } + + /** + * Only fail if a property of the given name does not + * exist in the current project. + * @param c property name + */ + public function setUnless($c) { + $this->unlessCondition = $c; + } + + /** + * @throws BuildException + */ + public function main() { + if ($this->testIfCondition() && $this->testUnlessCondition()) { + if ($this->message !== null) { + throw new BuildException($this->message); + } else { + throw new BuildException("No message"); + } + } + } + + /** + * Set a multiline message. + */ + public function addText($msg) { + if ($this->message === null) { + $this->message = ""; + } + $this->message .= $this->project->replaceProperties($msg); + } + + /** + * @return boolean + */ + private function testIfCondition() { + if ($this->ifCondition === null || $this->ifCondition === "") { + return true; + } + + return $this->project->getProperty($this->ifCondition) !== null; + } + + /** + * @return boolean + */ + private function testUnlessCondition() { + if ($this->unlessCondition === null || $this->unlessCondition === "") { + return true; + } + return $this->project->getProperty($this->unlessCondition) === null; + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/ForeachTask.php b/buildscripts/phing/classes/phing/tasks/system/ForeachTask.php new file mode 100644 index 00000000..a2a42665 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/ForeachTask.php @@ -0,0 +1,138 @@ +. + */ + +require_once 'phing/Task.php'; +include_once 'phing/tasks/system/PhingTask.php'; + +/** + * task + * + * Task definition for the foreach task. This task takes a list with + * delimited values, and executes a target with set param. + * + * Usage: + * + * + * Attributes: + * list --> The list of values to process, with the delimiter character, + * indicated by the "delimiter" attribute, separating each value. + * target --> The target to call for each token, passing the token as the + * parameter with the name indicated by the "param" attribute. + * param --> The name of the parameter to pass the tokens in as to the + * target. + * delimiter --> The delimiter string that separates the values in the "list" + * parameter. The default is ",". + * + * @author Jason Hines + * @author Hans Lellelid + * @version $Revision: 1.9 $ + * @package phing.tasks.system + */ +class ForeachTask extends Task { + + /** Delimter-separated list of values to process. */ + private $list; + + /** Name of parameter to pass to callee */ + private $param; + + /** Delimter that separates items in $list */ + private $delimiter = ','; + + /** + * PhingCallTask that will be invoked w/ calleeTarget. + * @var PhingCallTask + */ + private $callee; + + /** + * Target to execute. + * @var string + */ + private $calleeTarget; + + function init() { + $this->callee = $this->project->createTask("phingcall"); + $this->callee->setOwningTarget($this->getOwningTarget()); + $this->callee->setTaskName($this->getTaskName()); + $this->callee->setLocation($this->getLocation()); + $this->callee->init(); + } + + /** + * This method does the work. + * @return void + */ + function main() { + if ($this->list === null) { + throw new BuildException("Missing list to iterate through"); + } + if (trim($this->list) === '') { + return; + } + if ($this->param === null) { + throw new BuildException("You must supply a property name to set on each iteration in param"); + } + if ($this->calleeTarget === null) { + throw new BuildException("You must supply a target to perform"); + } + + $callee = $this->callee; + $callee->setTarget($this->calleeTarget); + $callee->setInheritAll(true); + $callee->setInheritRefs(true); + + $arr = explode($this->delimiter, $this->list); + + foreach ($arr as $value) { + $this->log("Setting param '$this->param' to value '$value'", PROJECT_MSG_VERBOSE); + $prop = $callee->createProperty(); + $prop->setOverride(true); + $prop->setName($this->param); + $prop->setValue($value); + $callee->main(); + } + } + + function setList($list) { + $this->list = (string) $list; + } + + function setTarget($target) { + $this->calleeTarget = (string) $target; + } + + function setParam($param) { + $this->param = (string) $param; + } + + function setDelimiter($delimiter) { + $this->delimiter = (string) $delimiter; + } + + /** + * @return Property + */ + function createProperty() { + return $this->callee->createProperty(); + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/IfTask.php b/buildscripts/phing/classes/phing/tasks/system/IfTask.php new file mode 100644 index 00000000..ab773355 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/IfTask.php @@ -0,0 +1,224 @@ +. + */ + +require_once 'phing/tasks/system/condition/ConditionBase.php'; +require_once 'phing/tasks/system/SequentialTask.php'; + +/** + * Perform some tasks based on whether a given condition holds true or + * not. + * + *

        This task is heavily based on the Condition framework that can + * be found in Ant 1.4 and later, therefore it cannot be used in + * conjunction with versions of Ant prior to 1.4.

        + * + *

        This task doesn't have any attributes, the condition to test is + * specified by a nested element - see the documentation of your + * task (see + * the + * online documentation for example) for a complete list of nested + * elements.

        + * + *

        Just like the task, only a single + * condition can be specified - you combine them using + * or conditions.

        + * + *

        In addition to the condition, you can specify three different + * child elements, , and + * . All three subelements are optional. + * + * Both and must not be + * used more than once inside the if task. Both are + * containers for Ant tasks, just like Ant's + * and + * tasks - in fact they are implemented using the same class as Ant's + * task.

        + * + * The behaves exactly like an + * except that it cannot contain the element + * inside of it. You may specify as may of these as you like, and the + * order they are specified is the order they are evaluated in. If the + * condition on the is false, then the first + * who's conditional evaluates to true + * will be executed. The will be executed + * only if the and all + * conditions are false. + * + *

        Use the following task to define the + * task before you use it the first time:

        + * + *
        
        + *   
        + * + *

        Crude Example

        + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * @author Stefan Bodewig + */ +class IfTask extends ConditionBase { + + + private $thenTasks = null; + private $elseIfTasks = array(); + private $elseTasks = null; + + /*** + * A nested Else if task + */ + public function addElseIf(ElseIfTask $ei) + { + $this->elseIfTasks[] = $ei; + } + + /** + * A nested element - a container of tasks that will + * be run if the condition holds true. + * + *

        Not required.

        + */ + public function addThen(SequentialTask $t) { + if ($this->thenTasks != null) { + throw new BuildException("You must not nest more than one into "); + } + $this->thenTasks = $t; + } + + /** + * A nested element - a container of tasks that will + * be run if the condition doesn't hold true. + * + *

        Not required.

        + */ + public function addElse(SequentialTask $e) { + if ($this->elseTasks != null) { + throw new BuildException("You must not nest more than one into "); + } + $this->elseTasks = $e; + } + + public function main() { + + if ($this->countConditions() > 1) { + throw new BuildException("You must not nest more than one condition into "); + } + if ($this->countConditions() < 1) { + throw new BuildException("You must nest a condition into "); + } + $conditions = $this->getConditions(); + $c = $conditions[0]; + + if ($c->evaluate()) { + if ($this->thenTasks != null) { + $this->thenTasks->main(); + } + } else { + $done = false; + $sz = count($this->elseIfTasks); + for($i=0; $i < $sz && !$done; $i++) { + $ei = $this->elseIfTasks[$i]; + if ($ei->evaluate()) { + $done = true; + $ei->main(); + } + } + + if (!$done && $this->elseTasks != null) { + $this->elseTasks->main(); + } + } + } +} + +/** + * "Inner" class for IfTask. + * This class has same basic structure as the IfTask, although of course it doesn't support tags. + */ +class ElseIfTask extends ConditionBase { + + private $thenTasks = null; + + public function addThen(SequentialTask $t) { + if ($this->thenTasks != null) { + throw new BuildException("You must not nest more than one into "); + } + $this->thenTasks = $t; + } + + /** + * @return boolean + */ + public function evaluate() { + + if ($this->countConditions() > 1) { + throw new BuildException("You must not nest more than one condition into "); + } + if ($this->countConditions() < 1) { + throw new BuildException("You must nest a condition into "); + } + + $conditions = $this->getConditions(); + $c = $conditions[0]; + + return $c->evaluate(); + } + + /** + * + */ + public function main() { + if ($this->thenTasks != null) { + $this->thenTasks->main(); + } + } + } \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/system/IncludePathTask.php b/buildscripts/phing/classes/phing/tasks/system/IncludePathTask.php new file mode 100644 index 00000000..ce9beee5 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/IncludePathTask.php @@ -0,0 +1,115 @@ +. + */ + +require_once 'phing/Task.php'; +include_once 'phing/types/Path.php'; + +/** + * Adds a normalized path to the PHP include_path. + * + * This provides a way to alter the include_path without editing any global php.ini settings + * or PHP_CLASSPATH environment variable. + * + * + * + * + * + * @author Hans Lellelid + * @version $Revision: 1.1 $ + * @package phing.tasks.system + */ +class IncludePathTask extends Task { + + /** + * Classname of task to register. + * This can be a dot-path -- relative to a location on PHP include_path. + * E.g. path.to.MyClass -> path/to/MyClass.php + * @var string + */ + private $classname; + + /** + * Path to add to PHP include_path to aid in finding specified class. + * @var Path + */ + private $classpath; + + /** + * Refid to already defined classpath + */ + private $classpathId; + + /** + * Set the classpath to be used when searching for component being defined + * + * @param Path $classpath An Path object containing the classpath. + */ + public function setClasspath(Path $classpath) { + if ($this->classpath === null) { + $this->classpath = $classpath; + } else { + $this->classpath->append($classpath); + } + } + + /** + * Create the classpath to be used when searching for component being defined + */ + public function createClasspath() { + if ($this->classpath === null) { + $this->classpath = new Path($this->project); + } + return $this->classpath->createPath(); + } + + /** + * Reference to a classpath to use when loading the files. + */ + public function setClasspathRef(Reference $r) { + $this->classpathId = $r->getRefId(); + $this->createClasspath()->setRefid($r); + } + + + /** Main entry point */ + public function main() { + + // Apparently casting to (string) no longer invokes __toString() automatically. + if (is_object($this->classpath)) { + $this->classpath = $this->classpath->__toString(); + } + + if (empty($this->classpath)) { + throw new BuildException("Provided classpath was empty."); + } + + $curr_parts = explode(PATH_SEPARATOR, get_include_path()); + $add_parts = explode(PATH_SEPARATOR, $this->classpath); + $new_parts = array_diff($add_parts, $curr_parts); + + if ($new_parts) { + $this->log("Prepending new include_path components: " . implode(PATH_SEPARATOR, $new_parts), PROJECT_MSG_VERBOSE); + set_include_path(implode(PATH_SEPARATOR, array_merge($new_parts, $curr_parts))); + } + + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/InputTask.php b/buildscripts/phing/classes/phing/tasks/system/InputTask.php new file mode 100644 index 00000000..a5e1fdb9 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/InputTask.php @@ -0,0 +1,146 @@ +. + */ + +require_once 'phing/Task.php'; +include_once 'phing/input/InputRequest.php'; +include_once 'phing/input/YesNoInputRequest.php'; +include_once 'phing/input/MultipleChoiceInputRequest.php'; + +/** + * Reads input from the InputHandler. + * + * @see Project::getInputHandler() + * @author Hans Lellelid (Phing) + * @author Ulrich Schmidt (Ant) + * @author Stefan Bodewig (Ant) + * @version $Revision: 1.6 $ + * @package phing.tasks.system + */ +class InputTask extends Task { + + private $validargs; + private $message = ""; // required + private $propertyName; // required + private $defaultValue; + private $promptChar; + + /** + * Defines valid input parameters as comma separated strings. If set, input + * task will reject any input not defined as accepted and requires the user + * to reenter it. Validargs are case sensitive. If you want 'a' and 'A' to + * be accepted you need to define both values as accepted arguments. + * + * @param validargs A comma separated String defining valid input args. + */ + public function setValidargs ($validargs) { + $this->validargs = $validargs; + } + + /** + * Defines the name of a property to be set from input. + * + * @param string $name Name for the property to be set from input + */ + public function setPropertyName($name) { + $this->propertyName = $name; + } + + /** + * Sets the Message which gets displayed to the user during the build run. + * @param message The message to be displayed. + */ + public function setMessage ($message) { + $this->message = $message; + } + + /** + * Set a multiline message. + */ + public function addText($msg) { + $this->message .= $this->project->replaceProperties($msg); + } + + /** + * Add a default value. + * @param string $v + */ + public function setDefaultValue($v) { + $this->defaultValue = $v; + } + + /** + * Set the character/string to use for the prompt. + * @param string $c + */ + public function setPromptChar($c) { + $this->promptChar = $c; + } + + /** + * Actual method executed by phing. + * @throws BuildException + */ + public function main() { + + if ($this->propertyName === null) { + throw new BuildException("You must specify a value for propertyName attribute."); + } + + if ($this->validargs !== null) { + $accept = preg_split('/[\s,]+/', $this->validargs); + + // is it a boolean (yes/no) inputrequest? + $yesno = false; + if (count($accept) == 2) { + $yesno = true; + foreach($accept as $ans) { + if(!StringHelper::isBoolean($ans)) { + $yesno = false; + break; + } + } + } + if ($yesno) $request = new YesNoInputRequest($this->message, $accept); + else $request = new MultipleChoiceInputRequest($this->message, $accept); + } else { + $request = new InputRequest($this->message); + } + + // default default is curr prop value + $request->setDefaultValue($this->project->getProperty($this->propertyName)); + + $request->setPromptChar($this->promptChar); + + // unless overridden... + if ($this->defaultValue !== null) { + $request->setDefaultValue($this->defaultValue); + } + + $this->project->getInputHandler()->handleInput($request); + + $value = $request->getInput(); + + if ($value !== null) { + $this->project->setUserProperty($this->propertyName, $value); + } + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/MatchingTask.php b/buildscripts/phing/classes/phing/tasks/system/MatchingTask.php new file mode 100644 index 00000000..c5497fbd --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/MatchingTask.php @@ -0,0 +1,361 @@ +. + */ + +require_once 'phing/Task.php'; +require_once 'phing/types/selectors/SelectorContainer.php'; +include_once 'phing/types/FileSet.php'; +include_once 'phing/types/PatternSet.php'; +include_once 'phing/util/DirectoryScanner.php'; + +/** + * This is an abstract task that should be used by all those tasks that + * require to include or exclude files based on pattern matching. + * + * This is very closely based on the ANT class of the same name. + * + * @author Hans Lellelid (Phing) + * @author Arnout J. Kuiper (Ant) + * @author Stefano Mazzocchi (Ant) + * @author Sam Ruby (Ant) + * @author Jon S. Stevens (Ant + * @author Stefan Bodewig (Ant) + * @author Bruce Atherton (Ant) + * @version $Revision: 1.4 $ + * @package phing.tasks.system + */ +abstract class MatchingTask extends Task implements SelectorContainer { + + /** @var boolean */ + protected $useDefaultExcludes = true; + + /** @var FileSet */ + protected $fileset; + + /** + * Create instance; set fileset to new FileSet. + */ + public function __construct() { + $this->fileset = new FileSet(); + } + + /** + * @see ProjectComponent::setProject() + */ + public function setProject(Project $project) { + parent::setProject($project); + $this->fileset->setProject($project); + } + + /** + * add a name entry on the include list + * @return PatternSetNameEntry + */ + public function createInclude() { + return $this->fileset->createInclude(); + } + + /** + * add a name entry on the include files list + * @return PatternSetNameEntry + */ + public function createIncludesFile() { + return $this->fileset->createIncludesFile(); + } + + /** + * add a name entry on the exclude list + * @return PatternSetNameEntry + */ + public function createExclude() { + return $this->fileset->createExclude(); + } + + /** + * add a name entry on the include files list + * @return PatternSetNameEntry + */ + public function createExcludesFile() { + return $this->fileset->createExcludesFile(); + } + + /** + * add a set of patterns + * @return PatternSet + */ + public function createPatternSet() { + return $this->fileset->createPatternSet(); + } + + /** + * Sets the set of include patterns. Patterns may be separated by a comma + * or a space. + * + * @param string $includes the string containing the include patterns + * @return void + */ + public function setIncludes($includes) { + $this->fileset->setIncludes($includes); + } + + /** + * Sets the set of exclude patterns. Patterns may be separated by a comma + * or a space. + * + * @param string $excludes the string containing the exclude patterns + */ + public function setExcludes($excludes) { + $this->fileset->setExcludes($excludes); + } + + + /** + * Sets whether default exclusions should be used or not. + * + * @param boolean $useDefaultExcludes "true"|"on"|"yes" when default exclusions + * should be used, "false"|"off"|"no" when they + * shouldn't be used. + */ + public function setDefaultexcludes($useDefaultExcludes) { + $this->useDefaultExcludes = (boolean) $useDefaultExcludes; + } + + /** + * Returns the directory scanner needed to access the files to process. + * @return DirectoryScanner + */ + protected function getDirectoryScanner(PhingFile $baseDir) { + $this->fileset->setDir($baseDir); + $this->fileset->setDefaultexcludes($this->useDefaultExcludes); + return $this->fileset->getDirectoryScanner($this->project); + } + + /** + * Sets the name of the file containing the includes patterns. + * + * @param PhingFile $includesfile A string containing the filename to fetch + * the include patterns from. + * @return void + */ + public function setIncludesfile(PhingFile $includesfile) { + $this->fileset->setIncludesfile(includesfile); + } + + /** + * Sets the name of the file containing the includes patterns. + * + * @param PhingFile $excludesfile A string containing the filename to fetch + * the include patterns from. + * @return void + */ + public function setExcludesfile(PhingFile $excludesfile) { + $this->fileset->setExcludesfile($excludesfile); + } + + /** + * Sets case sensitivity of the file system + * + * @param boolean $isCaseSensitive "true"|"on"|"yes" if file system is case + * sensitive, "false"|"off"|"no" when not. + * @return void + */ + public function setCaseSensitive($isCaseSensitive) { + $this->fileset->setCaseSensitive($isCaseSensitive); + } + + /** + * Sets whether or not symbolic links should be followed. + * + * @param boolean $followSymlinks whether or not symbolic links should be followed + * @return void + */ + public function setFollowSymlinks($followSymlinks) { + $this->fileset->setFollowSymlinks($followSymlinks); + } + + /** + * Indicates whether there are any selectors here. + * + * @return boolean Whether any selectors are in this container + */ + public function hasSelectors() { + return $this->fileset->hasSelectors(); + } + + /** + * Gives the count of the number of selectors in this container + * + * @return int The number of selectors in this container + */ + public function selectorCount() { + return $this->fileset->selectorCount(); + } + + /** + * Returns the set of selectors as an array. + * + * @return array FileSelector[] An array of selectors in this container + */ + public function getSelectors(Project $p) { + return $this->fileset->getSelectors($p); + } + + /** + * Returns an enumerator for accessing the set of selectors. + * + * @return an enumerator that goes through each of the selectors + */ + public function selectorElements() { + return $this->fileset->selectorElements(); + } + + /** + * Add a new selector into this container. + * + * @param FileSelector $selector the new selector to add + * @return void + */ + public function appendSelector(FileSelector $selector) { + $this->fileset->appendSelector($selector); + } + + /* Methods below all add specific selectors */ + + /** + * add a "Select" selector entry on the selector list + * @return SelectSelector + */ + public function createSelector() { + return $this->fileset->createSelector(); + } + + /** + * add an "And" selector entry on the selector list + * @return AndSelector + */ + public function createAnd() { + return $this->fileset->createAnd(); + } + + /** + * add an "Or" selector entry on the selector list + * @return void + */ + public function createOr() { + return $this->fileset->createOr(); + } + + /** + * add a "Not" selector entry on the selector list + * @return NotSelector + */ + public function createNot() { + return $this->fileset->createNot(); + } + + /** + * add a "None" selector entry on the selector list + * @return NoneSelector + */ + public function createNone() { + return $this->fileset->createNone(); + } + + /** + * add a majority selector entry on the selector list + * @return MajoritySelector + */ + public function createMajority() { + return $this->fileset->createMajority(); + } + + /** + * add a selector date entry on the selector list + * @return DateSelector + */ + public function createDate() { + return $this->fileset->addDate(); + } + + /** + * add a selector size entry on the selector list + * @return SizeSelector + */ + public function createSize() { + return $this->fileset->createSize(); + } + + /** + * add a selector filename entry on the selector list + * @return FilenameSelector + */ + public function createFilename() { + return $this->fileset->createFilename(); + } + + /** + * add an extended selector entry on the selector list + * @return ExtendSelector + */ + public function createCustom() { + return $this->fileset->createCustom(); + } + + /** + * add a contains selector entry on the selector list + * @return ContainsSelector + */ + public function createContains() { + return $this->fileset->createContains(); + } + + /** + * add a present selector entry on the selector list + * @return PresentSelector + */ + public function createPresent() { + return $this->fileset->createPresent(); + } + + /** + * add a depth selector entry on the selector list + * @return DepthSelector + */ + public function createDepth() { + return $this->fileset->createDepth(); + } + + /** + * add a depends selector entry on the selector list + * @return DependSelector + */ + public function createDepend() { + return $this->fileset->createDepend(); + } + + /** + * Accessor for the implict fileset. + * + * @return FileSet + */ + protected final function getImplicitFileSet() { + return $this->fileset; + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/MkdirTask.php b/buildscripts/phing/classes/phing/tasks/system/MkdirTask.php new file mode 100644 index 00000000..9d5c1f31 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/MkdirTask.php @@ -0,0 +1,64 @@ +. + */ + +require_once 'phing/Task.php'; +include_once 'phing/system/io/PhingFile.php'; + +/** + * Task to create a directory. + * + * @author Andreas Aderhold, andi@binarycloud.com + * @version $Revision: 1.8 $ + * @package phing.tasks.system + */ +class MkdirTask extends Task { + + /** directory to create*/ + private $dir; + + /** + * create the directory and all parents + * + * @throws BuildException if dir is somehow invalid, or creation failed. + */ + function main() { + if ($this->dir === null) { + throw new BuildException("dir attribute is required", $this->location); + } + if ($this->dir->isFile()) { + throw new BuildException("Unable to create directory as a file already exists with that name: " . $this->dir->getAbsolutePath()); + } + if (!$this->dir->exists()) { + $result = $this->dir->mkdirs(); + if (!$result) { + $msg = "Directory " . $this->dir->getAbsolutePath() . " creation was not successful for an unknown reason"; + throw new BuildException($msg, $this->location); + } + $this->log("Created dir: " . $this->dir->getAbsolutePath()); + } + } + + /** the directory to create; required. */ + function setDir(PhingFile $dir) { + $this->dir = $dir; + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/MoveTask.php b/buildscripts/phing/classes/phing/tasks/system/MoveTask.php new file mode 100644 index 00000000..a3e94536 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/MoveTask.php @@ -0,0 +1,197 @@ +. + */ + +require_once 'phing/tasks/system/CopyTask.php'; +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/system/io/IOException.php'; + +/** + * Moves a file or directory to a new file or directory. + * + * By default, the destination file is overwritten if it + * already exists. When overwrite is turned off, then files + * are only moved if the source file is newer than the + * destination file, or when the destination file does not + * exist. + * + * Source files and directories are only deleted when the file or + * directory has been copied to the destination successfully. + * + * @version $Revision: 1.8 $ + * @package phing.tasks.system + */ +class MoveTask extends CopyTask { + + function __construct() { + parent::__construct(); + $this->forceOverwrite = true; + } + + protected function doWork() { + + $copyMapSize = count($this->fileCopyMap); + if ($copyMapSize > 0) { + // files to move + $this->log("Moving $copyMapSize files to " . $this->destDir->getAbsolutePath()); + + foreach($this->fileCopyMap as $from => $to) { + if ($from == $to) { + $this->log("Skipping self-move of $from", $this->verbosity); + continue; + } + + $moved = false; + $f = new PhingFile($from); + $d = new PhingFile($to); + + $moved = false; + try { // try to rename + $this->log("Attempting to rename $from to $to", $this->verbosity); + $this->renameFile($f, $d, $this->forceOverwrite); + $moved = true; + } catch (IOException $ioe) { + $moved = false; + $this->log("Failed to rename $from to $to: " . $ioe->getMessage(), $this->verbosity); + } + + if (!$moved) { + try { // try to move + $this->log("Moving $from to $to", $this->verbosity); + + $this->fileUtils->copyFile($f, $d, $this->forceOverwrite, $this->preserveLMT, $this->filterChains, $this->getProject()); + + $f = new PhingFile($fromFile); + $f->delete(); + } catch (IOException $ioe) { + $msg = "Failed to move $from to $to: " . $ioe->getMessage(); + throw new BuildException($msg, $this->location); + } + } // if !moved + } // foreach fileCopyMap + } // if copyMapSize + + // handle empty dirs if appropriate + if ($this->includeEmpty) { + $e = array_keys($this->dirCopyMap); + $count = 0; + foreach ($e as $dir) { + $d = new PhingFile((string) $dir); + if (!$d->exists()) { + if (!$d->mkdirs()) { + $this->log("Unable to create directory " . $d->getAbsolutePath(), PROJECT_MSG_ERR); + } else { + $count++; + } + } + } + if ($count > 0) { + $this->log("moved $count empty director" . ($count == 1 ? "y" : "ies") . " to " . $this->destDir->getAbsolutePath()); + } + } + + if (count($this->filesets) > 0) { + // process filesets + foreach($this->filesets as $fs) { + $dir = $fs->getDir($this->project); + if ($this->okToDelete($dir)) { + $this->deleteDir($dir); + } + } + } + } + + /** Its only ok to delete a dir tree if there are no files in it. */ + private function okToDelete($d) { + $list = $d->listDir(); + if ($list === null) { + return false; // maybe io error? + } + + foreach($list as $s) { + $f = new PhingFile($d, $s); + if ($f->isDirectory()) { + if (!$this->okToDelete($f)) { + return false; + } + } else { + // found a file + return false; + } + } + return true; + } + + /** Go and delete the directory tree. */ + private function deleteDir($d) { + + $list = $d->listDir(); + if ($list === null) { + return; // on an io error list() can return null + } + + foreach($list as $fname) { + $f = new PhingFile($d, $fname); + if ($f->isDirectory()) { + $this->deleteDir($f); + } else { + throw new BuildException("UNEXPECTED ERROR - The file " . $f->getAbsolutePath() . " should not exist!"); + } + } + + $this->log("Deleting directory " . $d->getPath(), $this->verbosity); + try { + $d->delete(); + } catch (Exception $e) { + throw new BuildException("Unable to delete directory " . $d->__toString() . ": " . $e->getMessage()); + } + } + + /** + * Attempts to rename a file from a source to a destination. + * If overwrite is set to true, this method overwrites existing file + * even if the destination file is newer. + * Otherwise, the source f + * ile is renamed only if the destination file # + * is older than it. + */ + private function renameFile(PhingFile $sourceFile, PhingFile $destFile, $overwrite) { + $renamed = true; + + // ensure that parent dir of dest file exists! + $parent = $destFile->getParentFile(); + if ($parent !== null) { + if (!$parent->exists()) { + $parent->mkdirs(); + } + } + if ($destFile->exists()) { + try { + $destFile->delete(); + } catch (Exception $e) { + throw new BuildException("Unable to remove existing file " . $destFile->__toString() . ": " . $e->getMessage()); + } + } + $renamed = $sourceFile->renameTo($destFile); + + return $renamed; + } +} +?> diff --git a/buildscripts/phing/classes/phing/tasks/system/PhingCallTask.php b/buildscripts/phing/classes/phing/tasks/system/PhingCallTask.php new file mode 100644 index 00000000..34d4336d --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/PhingCallTask.php @@ -0,0 +1,139 @@ +. + */ + +require_once 'phing/Task.php'; + +/** + * Call another target in the same project. + * + *
        + *    
        + *      
        + *        
        + *        
        + *       
        + *    
        + *
        + *    
        + *      
        + *    
        + *  
        + * + *

        This only works as expected if neither property1 nor foo are + * defined in the project itself. + * + * @author Andreas Aderhold + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.9 $ + * @access public + * @package phing.tasks.system + */ +class PhingCallTask extends Task { + + private $callee; + private $subTarget; + // must match the default value of PhingTask#inheritAll + private $inheritAll = true; + // must match the default value of PhingTask#inheritRefs + private $inheritRefs = false; + + /** + * If true, pass all properties to the new Phing project. + * Defaults to true. Future use. + * @param boolean new value + */ + function setInheritAll($inherit) { + $this->inheritAll = (boolean) $inherit; + } + + /** + * If true, pass all references to the new Phing project. + * Defaults to false. Future use. + * + * @param boolean new value + */ + function setInheritRefs($inheritRefs) { + $this->inheritRefs = (boolean) $inheritRefs; + } + + /** + * init this task by creating new instance of the phing task and + * configuring it's by calling its own init method. + */ + function init() { + $this->callee = $this->project->createTask("phing"); + $this->callee->setOwningTarget($this->getOwningTarget()); + $this->callee->setTaskName($this->getTaskName()); + $this->callee->setLocation($this->getLocation()); + $this->callee->init(); + } + + /** + * hand off the work to the phing task of ours, after setting it up + * @throws BuildException on validation failure or if the target didn't + * execute + */ + function main() { + + $this->log("Running PhingCallTask for target '" . $this->subTarget . "'", PROJECT_MSG_DEBUG); + if ($this->callee === null) { + $this->init(); + } + + if ($this->subTarget === null) { + throw new BuildException("Attribute target is required.", $this->location); + } + + $this->callee->setPhingfile($this->project->getProperty("phing.file")); + $this->callee->setTarget($this->subTarget); + $this->callee->setInheritAll($this->inheritAll); + $this->callee->setInheritRefs($this->inheritRefs); + $this->callee->main(); + } + + /** + * Alias for createProperty + * @see createProperty() + */ + function createParam() { + if ($this->callee === null) { + $this->init(); + } + return $this->callee->createProperty(); + } + + /** + * Property to pass to the invoked target. + */ + function createProperty() { + if ($this->callee === null) { + $this->init(); + } + return $this->callee->createProperty(); + } + + /** + * Target to execute, required. + */ + function setTarget($target) { + $this->subTarget = (string) $target; + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/PhingTask.php b/buildscripts/phing/classes/phing/tasks/system/PhingTask.php new file mode 100644 index 00000000..e9883dd7 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/PhingTask.php @@ -0,0 +1,596 @@ +. +*/ + +include_once 'phing/Task.php'; +include_once 'phing/util/FileUtils.php'; +include_once 'phing/types/Reference.php'; +include_once 'phing/tasks/system/PropertyTask.php'; + +/** + * Task that invokes phing on another build file. + * + * Use this task, for example, if you have nested buildfiles in your project. Unlike + * AntTask, PhingTask can even support filesets: + * + *

        + *   
        + *    
        + *       
        + *      
        + *    
        + *   
        + * 
        + * + * @author Hans Lellelid + * @version $Revision: 1.20 $ + * @package phing.tasks.system + */ +class PhingTask extends Task { + + /** the basedir where is executed the build file */ + private $dir; + + /** build.xml (can be absolute) in this case dir will be ignored */ + private $phingFile; + + /** the target to call if any */ + protected $newTarget; + + /** should we inherit properties from the parent ? */ + private $inheritAll = true; + + /** should we inherit references from the parent ? */ + private $inheritRefs = false; + + /** the properties to pass to the new project */ + private $properties = array(); + + /** the references to pass to the new project */ + private $references = array(); + + /** The filesets that contain the files PhingTask is to be run on. */ + private $filesets = array(); + + /** the temporary project created to run the build file */ + private $newProject; + + /** Fail the build process when the called build fails? */ + private $haltOnFailure = false; + + /** + * If true, abort the build process if there is a problem with or in the target build file. + * Defaults to false. + * + * @param boolean new value + */ + public function setHaltOnFailure($hof) { + $this->haltOnFailure = (boolean) $hof; + } + + /** + * Creates a Project instance for the project to call. + * @return void + */ + public function init() { + $this->newProject = new Project(); + $tdf = $this->project->getTaskDefinitions(); + $this->newProject->addTaskDefinition("property", $tdf["property"]); + } + + /** + * Called in execute or createProperty if newProject is null. + * + *

        This can happen if the same instance of this task is run + * twice as newProject is set to null at the end of execute (to + * save memory and help the GC).

        + * + *

        Sets all properties that have been defined as nested + * property elements.

        + */ + private function reinit() { + $this->init(); + $count = count($this->properties); + for ($i = 0; $i < $count; $i++) { + $p = $this->properties[$i]; + $newP = $this->newProject->createTask("property"); + $newP->setName($p->getName()); + if ($p->getValue() !== null) { + $newP->setValue($p->getValue()); + } + if ($p->getFile() !== null) { + $newP->setFile($p->getFile()); + } + if ($p->getPrefix() !== null) { + $newP->setPrefix($p->getPrefix()); + } + if ($p->getRefid() !== null) { + $newP->setRefid($p->getRefid()); + } + if ($p->getEnvironment() !== null) { + $newP->setEnvironment($p->getEnvironment()); + } + if ($p->getUserProperty() !== null) { + $newP->setUserProperty($p->getUserProperty()); + } + if ($p->getOverride() !== null) { + $newP->setOverride($p->getOverride()); + } + $this->properties[$i] = $newP; + } + } + + /** + * Main entry point for the task. + * + * @return void + */ + public function main() { + + // Call Phing on the file set with the attribute "phingfile" + if ($this->phingFile !== null or $this->dir !== null) { + $this->processFile(); + } + + // if no filesets are given stop here; else process filesets + if (empty($this->filesets)) { + return; + } + + // preserve old settings + $savedDir = $this->dir; + $savedPhingFile = $this->phingFile; + $savedTarget = $this->newTarget; + $buildFailed = false; + + // set no specific target for files in filesets + // [HL] I'm commenting this out; I don't know why this should not be supported! + // $this->newTarget = null; + + foreach($this->filesets as $fs) { + + $ds = $fs->getDirectoryScanner($this->project); + + $fromDir = $fs->getDir($this->project); + $srcFiles = $ds->getIncludedFiles(); + + foreach($srcFiles as $fname) { + $f = new PhingFile($ds->getbasedir(), $fname); + $f = $f->getAbsoluteFile(); + $this->phingFile = $f->getAbsolutePath(); + $this->dir = $f->getParentFile(); + $this->processFile(); // run Phing! + } + } + + // side effect free programming ;-) + $this->dir = $savedDir; + $this->phingFile = $savedPhingFile; + $this->newTarget = $savedTarget; + + // [HL] change back to correct dir + if ($this->dir !== null) { + chdir($this->dir->getAbsolutePath()); + } + + } + + /** + * Execute phing file. + * + * @return void + */ + private function processFile() { + + $savedDir = $this->dir; + $savedPhingFile = $this->phingFile; + $savedTarget = $this->newTarget; + + try { + if ($this->newProject === null) { + $this->reinit(); + } + + if (($this->dir === null) && ($this->inheritAll)) { + $this->dir = $this->getProject()->getBaseDir(); + } + $this->initializeProject(); + if ($this->dir !== null) { + $this->newProject->setBaseDir($this->dir); + if ($savedDir !== null) { // has been set explicitly + $this->newProject->setInheritedProperty("project.basedir", $this->dir->getAbsolutePath()); + } + } else { + $this->dir = $this->getProject()->getBaseDir(); + } + + $this->overrideProperties(); + if ($this->phingFile === null) { + $this->phingFile = "build.xml"; + } + + $fu = new FileUtils(); + $file = $fu->resolveFile($this->dir, $this->phingFile); + $this->phingFile = $file->getAbsolutePath(); + + $this->log("Calling Buildfile '" . $this->phingFile . "' with target '" . $this->newTarget . "'"); + + $this->newProject->setUserProperty("phing.file", $this->phingFile); + + ProjectConfigurator::configureProject($this->newProject, new PhingFile($this->phingFile)); + + if ($this->newTarget === null) { + $this->newTarget = $this->newProject->getDefaultTarget(); + } + + // Are we trying to call the target in which we are defined? + if ($this->newProject->getBaseDir() == $this->project->getBaseDir() && + $this->newProject->getProperty("phing.file") == $this->project->getProperty("phing.file") && + $this->getOwningTarget() !== null && + $this->newTarget == $this->getOwningTarget()->getName()) { + + throw new BuildException("phing task calling its own parent target"); + } + + $this->addReferences(); + $this->newProject->executeTarget($this->newTarget); + + } catch (Exception $e) { + $buildFailed = true; + $this->log($e->getMessage(), PROJECT_MSG_ERR); + + // important!!! continue on to perform cleanup + // tasks. + } + + // } finally { + // restore values (prevent side-effects) + // !this must match code in catch () {} block! + $this->newProject = null; + $pkeys = array_keys($this->properties); + foreach($pkeys as $k) { + $this->properties[$k]->setProject(null); + } + $this->dir = $savedDir; + $this->phingFile = $savedPhingFile; + $this->newTarget = $savedTarget; + + // [HL] change back to correct dir + if ($this->dir !== null) { + chdir($this->dir->getAbsolutePath()); + } + + if ($this->haltOnFailure == true && $buildFailed == true) + throw new BuildException("Execution of the target buildfile failed. Aborting."); + } + + /** + * Configure the Project, i.e. make intance, attach build listeners + * (copy from father project), add Task and Datatype definitions, + * copy properties and references from old project if these options + * are set via the attributes of the XML tag. + * + * Developer note: + * This function replaces the old methods "init", "_reinit" and + * "_initializeProject". + * + * @access protected + */ + private function initializeProject() { + + $this->newProject->setInputHandler($this->project->getInputHandler()); + + foreach($this->project->getBuildListeners() as $listener) { + $this->newProject->addBuildListener($listener); + } + + /* Copy things from old project. Datatypes and Tasks are always + * copied, properties and references only if specified so/not + * specified otherwise in the XML definition. + */ + // Add Datatype definitions + foreach ($this->project->getDataTypeDefinitions() as $typeName => $typeClass) { + $this->newProject->addDataTypeDefinition($typeName, $typeClass); + } + + // Add Task definitions + foreach ($this->project->getTaskDefinitions() as $taskName => $taskClass) { + if ($taskClass == "propertytask") { + // we have already added this taskdef in init() + continue; + } + $this->newProject->addTaskDefinition($taskName, $taskClass); + } + + // set user-defined properties + $this->project->copyUserProperties($this->newProject); + + if (!$this->inheritAll) { + // set System built-in properties separately, + // b/c we won't inherit them. + $this->newProject->setSystemProperties(); + + } else { + // set all properties from calling project + $properties = $this->project->getProperties(); + foreach ($properties as $name => $value) { + if ($name == "basedir" || $name == "phing.file" || $name == "phing.version") { + // basedir and phing.file get special treatment in main() + continue; + } + // don't re-set user properties, avoid the warning message + if ($this->newProject->getProperty($name) === null){ + // no user property + $this->newProject->setNewProperty($name, $value); + } + } + + } + + } + + /** + * Override the properties in the new project with the one + * explicitly defined as nested elements here. + * @return void + * @throws BuildException + */ + private function overrideProperties() { + foreach(array_keys($this->properties) as $i) { + $p = $this->properties[$i]; + $p->setProject($this->newProject); + $p->main(); + } + $this->project->copyInheritedProperties($this->newProject); + } + + /** + * Add the references explicitly defined as nested elements to the + * new project. Also copy over all references that don't override + * existing references in the new project if inheritrefs has been + * requested. + * + * @return void + * @throws BuildException + */ + private function addReferences() { + + // parent project references + $projReferences = $this->project->getReferences(); + + $newReferences = $this->newProject->getReferences(); + + $subprojRefKeys = array(); + + if (count($this->references) > 0) { + for ($i=0, $count=count($this->references); $i < $count; $i++) { + $ref = $this->references[$i]; + $refid = $ref->getRefId(); + + if ($refid === null) { + throw new BuildException("the refid attribute is required" + . " for reference elements"); + } + if (!isset($projReferences[$refid])) { + $this->log("Parent project doesn't contain any reference '" + . $refid . "'", + PROJECT_MSG_WARN); + continue; + } + + $subprojRefKeys[] = $refid; + //thisReferences.remove(refid); + $toRefid = $ref->getToRefid(); + if ($toRefid === null) { + $toRefid = $refid; + } + $this->copyReference($refid, $toRefid); + } + } + + // Now add all references that are not defined in the + // subproject, if inheritRefs is true + if ($this->inheritRefs) { + + // get the keys that are were not used by the subproject + $unusedRefKeys = array_diff(array_keys($projReferences), $subprojRefKeys); + + foreach($unusedRefKeys as $key) { + if (isset($newReferences[$key])) { + continue; + } + $this->copyReference($key, $key); + } + } + } + + /** + * Try to clone and reconfigure the object referenced by oldkey in + * the parent project and add it to the new project with the key + * newkey. + * + *

        If we cannot clone it, copy the referenced object itself and + * keep our fingers crossed.

        + * + * @param string $oldKey + * @param string $newKey + * @return void + */ + private function copyReference($oldKey, $newKey) { + $orig = $this->project->getReference($oldKey); + if ($orig === null) { + $this->log("No object referenced by " . $oldKey . ". Can't copy to " + .$newKey, + PROJECT_SG_WARN); + return; + } + + $copy = clone $orig; + + if ($copy instanceof ProjectComponent) { + $copy->setProject($this->newProject); + } elseif (in_array('setProject', get_class_methods(get_class($copy)))) { + $copy->setProject($this->newProject); + } elseif ($copy instanceof Project) { + // don't copy the old "Project" itself + } else { + $msg = "Error setting new project instance for " + . "reference with id " . $oldKey; + throw new BuildException($msg); + } + + $this->newProject->addReference($newKey, $copy); + } + + /** + * If true, pass all properties to the new phing project. + * Defaults to true. + * + * @access public + */ + function setInheritAll($value) { + $this->inheritAll = (boolean) $value; + } + + /** + * If true, pass all references to the new phing project. + * Defaults to false. + * + * @access public + */ + function setInheritRefs($value) { + $this->inheritRefs = (boolean)$value; + } + + /** + * The directory to use as a base directory for the new phing project. + * Defaults to the current project's basedir, unless inheritall + * has been set to false, in which case it doesn't have a default + * value. This will override the basedir setting of the called project. + * + * @access public + */ + function setDir($d) { + if ( is_string($d) ) + $this->dir = new PhingFile($d); + else + $this->dir = $d; + } + + /** + * The build file to use. + * Defaults to "build.xml". This file is expected to be a filename relative + * to the dir attribute given. + * + * @access public + */ + function setPhingfile($s) { + // it is a string and not a file to handle relative/absolute + // otherwise a relative file will be resolved based on the current + // basedir. + $this->phingFile = $s; + } + + /** + * Alias function for setPhingfile + * + * @access public + */ + function setBuildfile($s) { + $this->setPhingFile($s); + } + + /** + * The target of the new Phing project to execute. + * Defaults to the new project's default target. + * + * @access public + */ + function setTarget($s) { + $this->newTarget = $s; + } + + /** + * Support for filesets; This method returns a reference to an instance + * of a FileSet object. + * + * @return FileSet + */ + function createFileSet() { + $num = array_push($this->filesets, new FileSet()); + return $this->filesets[$num-1]; + } + + /** + * Property to pass to the new project. + * The property is passed as a 'user property' + * + * @access public + */ + function createProperty() { + $p = new PropertyTask(); + $p->setFallback($this->newProject); + $p->setUserProperty(true); + $this->properties[] = $p; + return $p; + } + + /** + * Reference element identifying a data type to carry + * over to the new project. + * + * @access public + */ + function createReference() { + $num = array_push($this->references, new PhingReference()); + return $this->references[$num-1]; + } + +} + +/** + * Helper class that implements the nested + * element of and . + */ +class PhingReference extends Reference { + + private $targetid = null; + + /** + * Set the id that this reference to be stored under in the + * new project. + * + * @param targetid the id under which this reference will be passed to + * the new project */ + public function setToRefid($targetid) { + $this->targetid = $targetid; + } + + /** + * Get the id under which this reference will be stored in the new + * project + * + * @return the id of the reference in the new project. + */ + public function getToRefid() { + return $this->targetid; + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/PhpEvalTask.php b/buildscripts/phing/classes/phing/tasks/system/PhpEvalTask.php new file mode 100644 index 00000000..f1b72815 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/PhpEvalTask.php @@ -0,0 +1,169 @@ +. + */ + +require_once 'phing/Task.php'; + +/** + * Executes PHP function or evaluates expression and sets return value to a property. + * + * WARNING: + * This task can, of course, be abused with devastating effects. E.g. do not + * modify internal Phing classes unless you know what you are doing. + * + * @author Hans Lellelid + * @version $Revision: 1.7 $ + * @package phing.tasks.system + * + * @todo Add support for evaluating expressions + */ +class PhpEvalTask extends Task { + + protected $expression; // Expression to evaluate + protected $function; // Function to execute + protected $class; // Class containing function to execute + protected $returnProperty; // name of property to set to return value + protected $params = array(); // parameters for function calls + + /** Main entry point. */ + function main() { + + if ($this->function === null && $this->expression === null) { + throw new BuildException("You must specify a function to execute or PHP expression to evalute.", $this->location); + } + + if ($this->function !== null && $this->expression !== null) { + throw new BuildException("You can specify function or expression, but not both.", $this->location); + } + + if ($this->expression !== null && !empty($this->params)) { + throw new BuildException("You cannot use nested tags when evaluationg a PHP expression.", $this->location); + } + + $retval = null; + if ($this->function !== null) { + $retval = $this->callFunction(); + } elseif ($this->expression !== null) { + $retval = $this->evalExpression(); + } + + if ($this->returnProperty !== null) { + $this->project->setProperty($this->returnProperty, $retval); + } + } + + /** + * Calls function and returns results. + * @return mixed + */ + protected function callFunction() { + + if ($this->class !== null) { + // import the classname & unqualify it, if necessary + $this->class = Phing::import($this->class); + + $user_func = array($this->class, $this->function); + $h_func = $this->class . '::' . $this->function; // human-readable (for log) + } else { + $user_func = $this->function; + $h_func = $user_func; // human-readable (for log) + } + + // put parameters into simple array + $params = array(); + foreach($this->params as $p) { + $params[] = $p->getValue(); + } + + $this->log("Calling PHP function: " . $h_func . "()"); + foreach($params as $p) { + $this->log(" param: " . $p, PROJECT_MSG_VERBOSE); + } + + $return = call_user_func_array($user_func, $params); + return $return; + } + + /** + * Evaluates expression and returns resulting value. + * @return mixed + */ + protected function evalExpression() { + $this->log("Evaluating PHP expression: " . $this->expression); + if (!StringHelper::endsWith(';', trim($this->expression))) { + $this->expression .= ';'; + } + $retval = null; + eval('$retval = ' . $this->expression); + return $retval; + } + + /** Set function to execute */ + public function setFunction($f) { + $this->function = $f; + } + + /** Set [static] class which contains function to execute */ + public function setClass($c) { + $this->class = $c; + } + + /** Sets property name to set with return value of function or expression.*/ + public function setReturnProperty($r) { + $this->returnProperty = $r; + } + + /** Set PHP expression to evaluate. */ + public function addText($expression) { + $this->expression = $expression; + } + + /** Set PHP expression to evaluate. */ + public function setExpression($expression) { + $this->expression = $expression; + } + + /** Add a nested tag. */ + public function createParam() { + $p = new FunctionParam(); + $this->params[] = $p; + return $p; + } +} + +/** + * Supports the nested tag for PhpTask. + */ +class FunctionParam { + + private $val; + + public function setValue($v) { + $this->val = $v; + } + + public function addText($v) { + $this->val = $v; + } + + public function getValue() { + return $this->val; + } +} \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/system/PropertyPromptTask.php b/buildscripts/phing/classes/phing/tasks/system/PropertyPromptTask.php new file mode 100644 index 00000000..e7e12f33 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/PropertyPromptTask.php @@ -0,0 +1,201 @@ +. + */ + +require_once 'phing/Task.php'; +include_once 'phing/system/io/ConsoleReader.php'; + +/** + * Deprecated task that uses console to prompt user for property values. + * + * This class is very slightly simpler than the InputTask, but lacks the ability + * to use a non-console input handler. You should, therefore, use InputTask. This + * class can serve as a reference, but will be removed in the future. + * + * @author Hans Lellelid (Phing) + * @author Anthony J. Young-Garner (Ant) + * @version $Revision: 1.4 $ + * @package phing.tasks.system + * @deprecated - in favor of the more capable InputTask + */ +class PropertyPromptTask extends Task { + + private $propertyName; // required + private $defaultValue; + private $proposedValue; // required + private $promptText; // required + private $promptCharacter; + private $useExistingValue; + + /** + * Sets the prompt text that will be presented to the user. + * @param string $prompt + * @return void + */ + public function addText($prompt) { + $this->setPromptText($prompt); + } + + /** + * Run the PropertyPrompt task. + * @throws BuildException + */ + public function main() { + $this->proposedValue = $this->project->getProperty($this->propertyName); + $currentValue = $this->defaultValue; + if ($currentValue == "" && $this->proposedValue !== null) { $currentValue = $this->proposedValue; } + if (! (($this->useExistingValue === true) && ($this->proposedValue !== null))) { + + $this->log("Prompting user for " . $this->propertyName . ". " . $this->getDefaultMessage(), PROJECT_MSG_VERBOSE); + + print "\n" . $this->promptText . " [" . $currentValue . "] " . $this->promptCharacter . " "; + + /** future version should probably have hooks for validation of user input.*/ + $reader = new ConsoleReader(); + + try { + $this->proposedValue = $reader->readLine(); + } catch (IOException $e) { + $this->log("Prompt failed. Using default. (Failure reason: " . $e->getMessage().")"); + $this->proposedValue = $this->defaultValue; + } + + if (empty($this->proposedValue)) { + $this->log("No value specified, using default.", PROJECT_MSG_VERBOSE); + $this->proposedValue = $this->defaultValue; + } + + if (!empty($this->proposedValue)) { + $this->project->setProperty($this->propertyName, $this->proposedValue); + } + + } + } + + /** + * Returns a string to be inserted in the log message + * indicating whether a default response was specified + * in the build file. + */ + private function getDefaultMessage() { + if ($this->defaultValue == "") { + return "No default response specified."; + } else return "Default response is " . $this->defaultValue . "."; + } + + /** + * Returns defaultValue specified + * in this task for the Property + * being set. + * @return string + */ + public function getDefaultValue() { + return $this->defaultValue; + } + + /** + * Returns the terminating character used to + * punctuate the prompt text. + * @return string + */ + public function getPromptCharacter() { + return $this->promptCharacter; + } + + /** + * Returns text of the prompt. + * @return java.lang.String + */ + public function getPromptText() { + return $this->promptText; + } + + /** + * Returns name of the Ant Project Property + * being set by this task. + * @return string + */ + public function getPropertyName() { + return $this->propertyName; + } + /** + * Initializes this task. + */ + public function init() { + parent::init(); + $this->defaultValue = ""; + $this->promptCharacter = "?"; + $this->useExistingValue = false; + } + + /** + * Insert the method's description here. + * Creation date: (12/10/2001 8:16:16 AM) + * @return boolean + */ + public function isUseExistingValue() { + return $this->useExistingValue; + } + + /** + * Sets defaultValue for the Property + * being set by this task. + * @param string $newDefaultvalue + */ + public function setDefaultvalue($newDefaultvalue) { + $this->defaultValue = $newDefaultvalue; + } + + /** + * Sets the terminating character used to + * punctuate the prompt text (default is "?"). + * @param newPromptcharacter java.lang.String + */ + public function setPromptCharacter($newPromptcharacter) { + $this->promptCharacter = $newPromptcharacter; + } + + /** + * Sets text of the prompt. + * @param newPrompttext java.lang.String + */ + public function setPromptText($newPrompttext) { + $this->promptText = $newPrompttext; + } + + /** + * Specifies the Phing Project Property + * being set by this task. + * @param newPropertyname java.lang.String + */ + public function setPropertyName($newPropertyname) { + $this->propertyName = $newPropertyname; + } + + /** + * + * + * @param boolean newUseExistingValue + */ + public function setUseExistingValue($newUseExistingValue) { + $this->useExistingValue = $newUseExistingValue; + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/PropertyTask.php b/buildscripts/phing/classes/phing/tasks/system/PropertyTask.php new file mode 100644 index 00000000..d6168e44 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/PropertyTask.php @@ -0,0 +1,438 @@ +. + */ + +include_once 'phing/Task.php'; +include_once 'phing/system/util/Properties.php'; + +/** + * Task for setting properties in buildfiles. + * + * @author Andreas Aderhold + * @author Hans Lellelid + * @version $Revision$ + * @package phing.tasks.system + */ +class PropertyTask extends Task { + + /** name of the property */ + protected $name; + + /** value of the property */ + protected $value; + + protected $reference; + protected $env; // Environment + protected $file; + protected $ref; + protected $prefix; + protected $fallback; + + /** Whether to force overwrite of existing property. */ + protected $override = false; + + /** Whether property should be treated as "user" property. */ + protected $userProperty = false; + + /** + * Sets a the name of current property component + */ + function setName($name) { + $this->name = (string) $name; + } + + /** Get property component name. */ + function getName() { + return $this->name; + } + + /** + * Sets a the value of current property component. + * @param mixed Value of name, all scalars allowed + */ + function setValue($value) { + $this->value = (string) $value; + } + + /** + * Sets value of property to CDATA tag contents. + * @param string $values + * @since 2.2.0 + */ + public function addText($value) { + $this->setValue($value); + } + + /** Get the value of current property component. */ + function getValue() { + return $this->value; + } + + /** Set a file to use as the source for properties. */ + function setFile($file) { + if (is_string($file)) { + $file = new PhingFile($file); + } + $this->file = $file; + } + + /** Get the PhingFile that is being used as property source. */ + function getFile() { + return $this->file; + } + + function setRefid(Reference $ref) { + $this->reference = $ref; + } + + function getRefid() { + return $this->reference; + } + + /** + * Prefix to apply to properties loaded using file. + * A "." is appended to the prefix if not specified. + * @param string $prefix prefix string + * @return void + * @since 2.0 + */ + public function setPrefix($prefix) { + $this->prefix = $prefix; + if (!StringHelper::endsWith(".", $prefix)) { + $this->prefix .= "."; + } + } + + /** + * @return string + * @since 2.0 + */ + public function getPrefix() { + return $this->prefix; + } + + /** + * the prefix to use when retrieving environment variables. + * Thus if you specify environment="myenv" + * you will be able to access OS-specific + * environment variables via property names "myenv.PATH" or + * "myenv.TERM". + *

        + * Note that if you supply a property name with a final + * "." it will not be doubled. ie environment="myenv." will still + * allow access of environment variables through "myenv.PATH" and + * "myenv.TERM". This functionality is currently only implemented + * on select platforms. Feel free to send patches to increase the number of platforms + * this functionality is supported on ;).
        + * Note also that properties are case sensitive, even if the + * environment variables on your operating system are not, e.g. it + * will be ${env.Path} not ${env.PATH} on Windows 2000. + * @param env prefix + */ + function setEnvironment($env) { + $this->env = (string) $env; + } + + function getEnvironment() { + return $this->env; + } + + /** + * Set whether this is a user property (ro). + * This is deprecated in Ant 1.5, but the userProperty attribute + * of the class is still being set via constructor, so Phing will + * allow this method to function. + * @param boolean $v + */ + function setUserProperty($v) { + $this->userProperty = (boolean) $v; + } + + function getUserProperty() { + return $this->userProperty; + } + + function setOverride($v) { + $this->override = (boolean) $v; + } + + function getOverride() { + return $this->override; + } + + function toString() { + return (string) $this->value; + } + + /** + * @param Project $p + */ + function setFallback($p) { + $this->fallback = $p; + } + + function getFallback() { + return $this->fallback; + } + /** + * set the property in the project to the value. + * if the task was give a file or env attribute + * here is where it is loaded + */ + function main() { + if ($this->name !== null) { + if ($this->value === null && $this->ref === null) { + throw new BuildException("You must specify value or refid with the name attribute", $this->getLocation()); + } + } else { + if ($this->file === null && $this->env === null ) { + throw new BuildException("You must specify file or environment when not using the name attribute", $this->getLocation()); + } + } + + if ($this->file === null && $this->prefix !== null) { + throw new BuildException("Prefix is only valid when loading from a file.", $this->getLocation()); + } + + if (($this->name !== null) && ($this->value !== null)) { + $this->addProperty($this->name, $this->value); + } + + if ($this->file !== null) { + $this->loadFile($this->file); + } + + if ( $this->env !== null ) { + $this->loadEnvironment($this->env); + } + + if (($this->name !== null) && ($this->ref !== null)) { + // get the refereced property + try { + $this->addProperty($this->name, $this->reference->getReferencedObject($this->project)->toString()); + } catch (BuildException $be) { + if ($this->fallback !== null) { + $this->addProperty($this->name, $this->reference->getReferencedObject($this->fallback)->toString()); + } else { + throw $be; + } + } + } + } + + /** + * load the environment values + * @param string $prefix prefix to place before them + */ + protected function loadEnvironment($prefix) { + + $props = new Properties(); + if ( substr($prefix, strlen($prefix)-1) == '.' ) { + $prefix .= "."; + } + $this->log("Loading Environment $prefix", PROJECT_MSG_VERBOSE); + foreach($_ENV as $key => $value) { + $props->setProperty($prefix . '.' . $key, $value); + } + $this->addProperties($props); + } + + /** + * iterate through a set of properties, + * resolve them then assign them + */ + protected function addProperties($props) { + $this->resolveAllProperties($props); + foreach($props->keys() as $name) { + $value = $props->getProperty($name); + $v = $this->project->replaceProperties($value); + if ($this->prefix !== null) { + $name = $this->prefix . $name; + } + $this->addProperty($name, $v); + } + } + + /** + * add a name value pair to the project property set + * @param string $name name of property + * @param string $value value to set + */ + protected function addProperty($name, $value) { + if ($this->userProperty) { + if ($this->project->getUserProperty($name) === null || $this->override) { + $this->project->setInheritedProperty($name, $value); + } else { + $this->log("Override ignored for " . $name, PROJECT_MSG_VERBOSE); + } + } else { + if ($this->override) { + $this->project->setProperty($name, $value); + } else { + $this->project->setNewProperty($name, $value); + } + } + } + + /** + * load properties from a file. + * @param PhingFile $file + */ + protected function loadFile(PhingFile $file) { + $props = new Properties(); + $this->log("Loading ". $file->getAbsolutePath(), PROJECT_MSG_INFO); + try { // try to load file + if ($file->exists()) { + $props->load($file); + $this->addProperties($props); + } else { + $this->log("Unable to find property file: ". $file->getAbsolutePath() ."... skipped", PROJECT_MSG_WARN); + } + } catch (IOException $ioe) { + throw new BuildException("Could not load properties from file.", $ioe); + } + } + + /** + * Given a Properties object, this method goes through and resolves + * any references to properties within the object. + * + * @param Properties $props The collection of Properties that need to be resolved. + * @return void + */ + protected function resolveAllProperties(Properties $props) { + + $keys = $props->keys(); + + while(count($keys)) { + + // There may be a nice regex/callback way to handle this + // replacement, but at the moment it is pretty complex, and + // would probably be a lot uglier to work into a preg_replace_callback() + // system. The biggest problem is the fact that a resolution may require + // multiple passes. + + $name = array_shift($keys); + $value = $props->getProperty($name); + $resolved = false; + + while(!$resolved) { + + $fragments = array(); + $propertyRefs = array(); + + // [HL] this was ::parsePropertyString($this->value ...) ... this seems wrong + self::parsePropertyString($value, $fragments, $propertyRefs); + + $resolved = true; + if (count($propertyRefs) !== 0) { + + $sb = ""; + + $i = $fragments; + $j = $propertyRefs; + while(count($i)) { + $fragment = array_shift($i); + if ($fragment === null) { + $propertyName = array_shift($j); + + if ($propertyName === $name) { + // Should we maybe just log this as an error & move on? + // $this->log("Property ".$name." was circularly defined.", PROJECT_MSG_ERR); + throw new BuildException("Property ".$name." was circularly defined."); + } + + $fragment = $this->getProject()->getProperty($propertyName); + if ($fragment === null) { + if ($props->containsKey($propertyName)) { + $fragment = $props->getProperty($propertyName); + $resolved = false; // parse again (could have been replaced w/ another var) + } else { + $fragment = "\${".$propertyName."}"; + } + } + } + $sb .= $fragment; + } + + $this->log("Resolved Property \"$value\" to \"$sb\"", PROJECT_MSG_DEBUG); + $value = $sb; + $props->setProperty($name, $value); + + } // if (count($propertyRefs)) + + } // while (!$resolved) + + } // while (count($keys) + } + + + /** + * This method will parse a string containing ${value} style + * property values into two lists. The first list is a collection + * of text fragments, while the other is a set of string property names + * null entries in the first list indicate a property reference from the + * second list. + * + * This is slower than regex, but useful for this class, which has to handle + * multiple parsing passes for properties. + * + * @param string $value The string to be scanned for property references + * @param array &$fragments The found fragments + * @param array &$propertyRefs The found refs + */ + protected function parsePropertyString($value, &$fragments, &$propertyRefs) { + + $prev = 0; + $pos = 0; + + while (($pos = strpos($value, '$', $prev)) !== false) { + + if ($pos > $prev) { + array_push($fragments, StringHelper::substring($value, $prev, $pos-1)); + } + if ($pos === (strlen($value) - 1)) { + array_push($fragments, '$'); + $prev = $pos + 1; + } elseif ($value{$pos+1} !== '{' ) { + + // the string positions were changed to value-1 to correct + // a fatal error coming from function substring() + array_push($fragments, StringHelper::substring($value, $pos, $pos + 1)); + $prev = $pos + 2; + } else { + $endName = strpos($value, '}', $pos); + if ($endName === false) { + throw new BuildException("Syntax error in property: $value"); + } + $propertyName = StringHelper::substring($value, $pos + 2, $endName-1); + array_push($fragments, null); + array_push($propertyRefs, $propertyName); + $prev = $endName + 1; + } + } + + if ($prev < strlen($value)) { + array_push($fragments, StringHelper::substring($value, $prev)); + } + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/ReflexiveTask.php b/buildscripts/phing/classes/phing/tasks/system/ReflexiveTask.php new file mode 100644 index 00000000..dc7cfeb7 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/ReflexiveTask.php @@ -0,0 +1,155 @@ +. + */ + +require_once 'phing/Task.php'; + +/** + * This task is for using filter chains to make changes to files and overwrite the original files. + * + * This task was created to serve the need for "cleanup" tasks -- e.g. a ReplaceRegexp task or strip task + * being used to modify files and then overwrite the modified files. In many (most?) cases you probably + * should just use a copy task to preserve the original source files, but this task supports situations + * where there is no src vs. build directory, and modifying source files is actually desired. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * @author Hans Lellelid + * @version $Revision: 1.11 $ + * @package phing.tasks.system + */ +class ReflexiveTask extends Task { + + /** Single file to process. */ + private $file; + + /** Any filesets that should be processed. */ + private $filesets = array(); + + /** Any filters to be applied before append happens. */ + private $filterChains = array(); + + /** Alias for setFrom() */ + function setFile(PhingFile $f) { + $this->file = $f; + } + + /** Nested creator, adds a set of files (nested fileset attribute). */ + function createFileSet() { + $num = array_push($this->filesets, new FileSet()); + return $this->filesets[$num-1]; + } + + /** + * Creates a filterchain + * + * @return object The created filterchain object + */ + function createFilterChain() { + $num = array_push($this->filterChains, new FilterChain($this->project)); + return $this->filterChains[$num-1]; + } + + /** Append the file(s). */ + function main() { + + if ($this->file === null && empty($this->filesets)) { + throw new BuildException("You must specify a file or fileset(s) for the task."); + } + + // compile a list of all files to modify, both file attrib and fileset elements + // can be used. + + $files = array(); + + if ($this->file !== null) { + $files[] = $this->file; + } + + if (!empty($this->filesets)) { + $filenames = array(); + foreach($this->filesets as $fs) { + try { + $ds = $fs->getDirectoryScanner($this->project); + $filenames = $ds->getIncludedFiles(); // get included filenames + $dir = $fs->getDir($this->project); + foreach ($filenames as $fname) { + $files[] = new PhingFile($dir, $fname); + } + } catch (BuildException $be) { + $this->log($be->getMessage(), PROJECT_MSG_WARN); + } + } + } + + $this->log("Applying reflexive processing to " . count($files) . " files."); + + // These "slots" allow filters to retrieve information about the currently-being-process files + $slot = $this->getRegisterSlot("currentFile"); + $basenameSlot = $this->getRegisterSlot("currentFile.basename"); + + + foreach($files as $file) { + // set the register slots + + $slot->setValue($file->getPath()); + $basenameSlot->setValue($file->getName()); + + // 1) read contents of file, pulling through any filters + $in = null; + try { + $contents = ""; + $in = FileUtils::getChainedReader(new FileReader($file), $this->filterChains, $this->project); + while(-1 !== ($buffer = $in->read())) { + $contents .= $buffer; + } + $in->close(); + } catch (Exception $e) { + if ($in) $in->close(); + $this->log("Erorr reading file: " . $e->getMessage(), PROJECT_MSG_WARN); + } + + try { + // now create a FileWriter w/ the same file, and write to the file + $out = new FileWriter($file); + $out->write($contents); + $out->close(); + $this->log("Applying reflexive processing to " . $file->getPath(), PROJECT_MSG_VERBOSE); + } catch (Exception $e) { + if ($out) $out->close(); + $this->log("Error writing file back: " . $e->getMessage(), PROJECT_MSG_WARN); + } + + } + + } + +} \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/system/ResolvePathTask.php b/buildscripts/phing/classes/phing/tasks/system/ResolvePathTask.php new file mode 100644 index 00000000..b468afb5 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/ResolvePathTask.php @@ -0,0 +1,122 @@ +. + */ + +require_once 'phing/Task.php'; + +/** + * Task for resolving relative paths and setting absolute path in property value. + * + * This task was created to address a need for resolving absolute paths of files / directories. + * In many cases a relative directory (e.g. "./build") is specified, but it needs to be treated + * as an absolute path since other build files (e.g. in subdirs) should all be using the same + * path -- and not treating it as a relative path to their own directory. + * + * + * + * + * Resolved [absolute] path: ${absolute_path} + * + * + * TODO: + * - Possibly integrate this with PackageAsPath, for handling/resolving dot-path paths. + * + * @author Hans Lellelid + * @version $Revision: 1.6 $ + * @package phing.tasks.system + */ +class ResolvePathTask extends Task { + + /** Name of property to set. */ + private $propertyName; + + /** The [possibly] relative file/path that needs to be resolved. */ + private $file; + + /** Base directory used for resolution. */ + private $dir; + + /** + * Set the name of the property to set. + * @param string $v Property name + * @return void + */ + public function setPropertyName($v) { + $this->propertyName = $v; + } + + /** + * Sets a base dir to use for resolution. + * @param PhingFile $d + */ + function setDir(PhingFile $d) { + $this->dir = $d; + } + + /** + * Sets a path (file or directory) that we want to resolve. + * This is the same as setFile() -- just more generic name so that it's + * clear that you can also use it to set directory. + * @param string $f + * @see setFile() + */ + function setPath($f) { + $this->file = $f; + } + + /** + * Sets a file that we want to resolve. + * @param string $f + */ + function setFile($f) { + $this->file = $f; + } + + /** + * Perform the resolution & set property. + */ + public function main() { + + if (!$this->propertyName) { + throw new BuildException("You must specify the propertyName attribute", $this->getLocation()); + } + + // Currently only files are supported + if ($this->file === null) { + throw new BuildException("You must specify a path to resolve", $this->getLocation()); + } + + $fs = FileSystem::getFileSystem(); + + // if dir attribute was specified then we should + // use that as basedir to which file was relative. + // -- unless the file specified is an absolute path + if ($this->dir !== null && !$fs->isAbsolute(new PhingFile($this->file))) { + $resolved = new PhingFile($this->dir->getPath(), $this->file); + } else { + // otherwise just resolve it relative to project basedir + $resolved = $this->project->resolveFile($this->file); + } + + $this->log("Resolved " . $this->file . " to " . $resolved->getAbsolutePath(), PROJECT_MSG_INFO); + $this->project->setProperty($this->propertyName, $resolved->getAbsolutePath()); + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/SequentialTask.php b/buildscripts/phing/classes/phing/tasks/system/SequentialTask.php new file mode 100644 index 00000000..50327e3f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/SequentialTask.php @@ -0,0 +1,57 @@ +. + */ + +require_once 'phing/Task.php'; +require_once 'phing/TaskContainer.php'; + +/** + * Sequential is a container task that contains other Phing Task objects. + * + * The sequential task has no attributes and does not support any nested + * elements apart from Ant tasks. Any valid Ant task may be embedded within the + * sequential task. + * + * @since 2.1.2 + */ +class SequentialTask extends Task implements TaskContainer { + + /** Optional Vector holding the nested tasks */ + private $nestedTasks = array(); + + /** + * Add a nested task to Sequential. + * @param Task $nestedTask Nested task to execute Sequential + */ + public function addTask(Task $nestedTask) { + $this->nestedTasks[] = $nestedTask; + } + + /** + * Execute all nestedTasks. + * @throws BuildException if one of the nested tasks fails. + */ + public function main() { + foreach($this->nestedTasks as $task) { + $task->perform(); + } + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/TaskdefTask.php b/buildscripts/phing/classes/phing/tasks/system/TaskdefTask.php new file mode 100644 index 00000000..4a90e106 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/TaskdefTask.php @@ -0,0 +1,127 @@ +. + */ + +require_once 'phing/Task.php'; + +/** + * Register a task for use within a buildfile. + * + * This is for registering your own tasks -- or any non-core Task -- for use within a buildfile. + * If you find that you are using a particular class frequently, you may want to edit the + * phing/tasks/defaults.properties file so that it is included by default. You may also + * want to submit it (if LGPL or compatible license) to be included in Phing distribution. + * + *

        + *   
        + *   .
        + *   .
        + *   
        + * 
        + * + * TODO: + * -- possibly refactor since this is almost the same as TypeDefTask + * (right now these are just too simple to really justify creating an abstract class) + * + * @author Hans Lellelid + * @version $Revision: 1.11 $ + * @package phing.tasks.system + */ +class TaskdefTask extends Task { + + /** Tag name for task that will be used in XML */ + private $name; + + /** + * Classname of task to register. + * This can be a dot-path -- relative to a location on PHP include_path. + * E.g. path.to.MyClass -> path/to/MyClass.php + * @var string + */ + private $classname; + + /** + * Path to add to PHP include_path to aid in finding specified class. + * @var Path + */ + private $classpath; + + /** + * Refid to already defined classpath + */ + private $classpathId; + + /** + * Set the classpath to be used when searching for component being defined + * + * @param Path $classpath An Path object containing the classpath. + */ + public function setClasspath(Path $classpath) { + if ($this->classpath === null) { + $this->classpath = $classpath; + } else { + $this->classpath->append($classpath); + } + } + + /** + * Create the classpath to be used when searching for component being defined + */ + public function createClasspath() { + if ($this->classpath === null) { + $this->classpath = new Path($this->project); + } + return $this->classpath->createPath(); + } + + /** + * Reference to a classpath to use when loading the files. + */ + public function setClasspathRef(Reference $r) { + $this->classpathId = $r->getRefId(); + $this->createClasspath()->setRefid($r); + } + + /** + * Sets the name that will be used in XML buildfile. + * @param string $name + */ + public function setName($name) { + $this->name = $name; + } + + /** + * Sets the class name / dotpath to use. + * @param string $class + */ + public function setClassname($class) { + $this->classname = $class; + } + + /** Main entry point */ + public function main() { + if ($this->name === null || $this->classname === null) { + throw new BuildException("You must specify name and class attributes for ."); + } + $this->log("Task " . $this->name . " will be handled by class " . $this->classname, PROJECT_MSG_VERBOSE); + $this->project->addTaskDefinition($this->name, $this->classname, $this->classpath); + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/TouchTask.php b/buildscripts/phing/classes/phing/tasks/system/TouchTask.php new file mode 100644 index 00000000..6c6c4080 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/TouchTask.php @@ -0,0 +1,170 @@ +. + */ + +require_once 'phing/Task.php'; +include_once 'phing/util/DirectoryScanner.php'; +include_once 'phing/types/FileSet.php'; +include_once 'phing/util/FileUtils.php'; +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/system/io/IOException.php'; + +/** + * Touch a file and/or fileset(s); corresponds to the Unix touch command. + * + * If the file to touch doesn't exist, an empty one is created. + * + * @version $Revision: 1.12 $ + * @package phing.tasks.system + */ +class TouchTask extends Task { + + private $file; + private $millis = -1; + private $dateTime; + private $filesets = array(); + private $fileUtils; + + function __construct() { + $this->fileUtils = new FileUtils(); + } + + /** + * Sets a single source file to touch. If the file does not exist + * an empty file will be created. + */ + function setFile(PhingFile $file) { + $this->file = $file; + } + + /** + * the new modification time of the file + * in milliseconds since midnight Jan 1 1970. + * Optional, default=now + */ + function setMillis($millis) { + $this->millis = (int) $millis; + } + + /** + * the new modification time of the file + * in the format MM/DD/YYYY HH:MM AM or PM; + * Optional, default=now + */ + function setDatetime($dateTime) { + $this->dateTime = (string) $dateTime; + } + + /** + * Nested creator, adds a set of files (nested fileset attribute). + * @return FileSet + */ + function createFileSet() { + $num = array_push($this->filesets, new FileSet()); + return $this->filesets[$num-1]; + } + + /** + * Execute the touch operation. + */ + function main() { + $savedMillis = $this->millis; + + if ($this->file === null && count($this->filesets) === 0) { + throw new BuildException("Specify at least one source - a file or a fileset."); + } + + if ($this->file !== null && $this->file->exists() && $this->file->isDirectory()) { + throw new BuildException("Use a fileset to touch directories."); + } + + try { // try to touch file + if ($this->dateTime !== null) { + $this->setMillis(strtotime($this->dateTime)); + if ($this->millis < 0) { + throw new BuildException("Date of {$this->dateTime} results in negative milliseconds value relative to epoch (January 1, 1970, 00:00:00 GMT)."); + } + } + $this->_touch(); + } catch (Exception $ex) { + throw new BuildException("Error touch()ing file", $ex, $this->location); + } + + $this->millis = $savedMillis; + + } + + /** + * Does the actual work. + */ + function _touch() { + if ($this->file !== null) { + if (!$this->file->exists()) { + $this->log("Creating " . $this->file->__toString(), PROJECT_MSG_INFO); + try { // try to create file + $this->file->createNewFile(); + } catch(IOException $ioe) { + throw new BuildException("Error creating new file " . $this->file->__toString(), $ioe, $this->location); + } + } + } + + $resetMillis = false; + if ($this->millis < 0) { + $resetMillis = true; + $this->millis = Phing::currentTimeMillis(); + } + + if ($this->file !== null) { + $this->touchFile($this->file); + } + + // deal with the filesets + foreach($this->filesets as $fs) { + + $ds = $fs->getDirectoryScanner($this->getProject()); + $fromDir = $fs->getDir($this->getProject()); + + $srcFiles = $ds->getIncludedFiles(); + $srcDirs = $ds->getIncludedDirectories(); + + for ($j=0,$_j=count($srcFiles); $j < $_j; $j++) { + $this->touchFile(new PhingFile($fromDir, (string) $srcFiles[$j])); + } + + for ($j=0,$_j=count($srcDirs); $j < $_j ; $j++) { + $this->touchFile(new PhingFile($fromDir, (string) $srcDirs[$j])); + } + } + + if ($resetMillis) { + $this->millis = -1; + } + } + + private function touchFile($file) { + if ( !$file->canWrite() ) { + throw new BuildException("Can not change modification date of read-only file " . $file->__toString()); + } + $file->setLastModified($this->millis); + } + +} + diff --git a/buildscripts/phing/classes/phing/tasks/system/TstampTask.php b/buildscripts/phing/classes/phing/tasks/system/TstampTask.php new file mode 100644 index 00000000..9341c3dd --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/TstampTask.php @@ -0,0 +1,168 @@ +. + */ + +require_once 'phing/Task.php'; + +/** + * Sets properties to the current time, or offsets from the current time. + * The default properties are TSTAMP, DSTAMP and TODAY; + * + * Based on Ant's Tstamp task. + * + * @author Michiel Rook + * @version $Revision: 1.6 $ + * @package phing.tasks.system + * @since 2.2.0 + */ +class TstampTask extends Task +{ + private $customFormats = array(); + + private $prefix = ""; + + /** + * Set a prefix for the properties. If the prefix does not end with a "." + * one is automatically added. + * @param prefix the prefix to use. + */ + public function setPrefix($prefix) + { + $this->prefix = $prefix; + + if (!empty($this->prefix)) + { + $this->prefix.= "."; + } + } + + /** + * Adds a custom format + * + * @param TstampCustomFormat custom format + */ + public function addFormat(TstampCustomFormat $cf) + { + $this->customFormats[] = $cf; + } + + /** + * Create the timestamps. Custom ones are done before + * the standard ones. + * + * @throws BuildException + */ + public function main() + { + foreach ($this->customFormats as $cf) + { + $cf->execute($this); + } + + $dstamp = strftime('%Y%m%d'); + $this->prefixProperty('DSTAMP', $dstamp); + + $tstamp = strftime('%H%M'); + $this->prefixProperty('TSTAMP', $tstamp); + + $today = strftime('%B %d %Y'); + $this->prefixProperty('TODAY', $today); + } + + /** + * helper that encapsulates prefix logic and property setting + * policy (i.e. we use setNewProperty instead of setProperty). + */ + public function prefixProperty($name, $value) + { + $this->getProject()->setNewProperty($this->prefix . $name, $value); + } +} + +class TstampCustomFormat +{ + private $propertyName = ""; + private $pattern = ""; + private $locale = ""; + + /** + * The property to receive the date/time string in the given pattern + * + * @param propertyName the name of the property. + */ + public function setProperty($propertyName) + { + $this->propertyName = $propertyName; + } + + /** + * The date/time pattern to be used. The values are as + * defined by the PHP strftime() function. + * + * @param pattern + */ + public function setPattern($pattern) + { + $this->pattern = $pattern; + } + + /** + * The locale used to create date/time string. + * + * @param locale + */ + public function setLocale($locale) + { + $this->locale = $locale; + } + + /** + * validate parameter and execute the format. + * + * @param TstampTask reference to task + */ + public function execute(TstampTask $tstamp) + { + if (empty($this->propertyName)) + { + throw new BuildException("property attribute must be provided"); + } + + if (empty($this->pattern)) + { + throw new BuildException("pattern attribute must be provided"); + } + + if (!empty($this->locale)) + { + setlocale(LC_ALL, $this->locale); + } + + $value = strftime($this->pattern); + $tstamp->prefixProperty($this->propertyName, $value); + + if (!empty($this->locale)) + { + // reset locale + setlocale(LC_ALL, NULL); + } + } +} +?> diff --git a/buildscripts/phing/classes/phing/tasks/system/TypedefTask.php b/buildscripts/phing/classes/phing/tasks/system/TypedefTask.php new file mode 100644 index 00000000..de058c90 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/TypedefTask.php @@ -0,0 +1,125 @@ +. + */ + +require_once 'phing/Task.php'; + +/** + * Register a datatype for use within a buildfile. + * + * This is for registering your own datatypes for use within a buildfile. + * + * If you find that you are using a particular class frequently, you may want to edit the + * phing/types/defaults.properties file so that it is included by default. You may also + * want to submit it (if LGPL or compatible license) to be included in Phing distribution. + * + *
        + *   
        + *   .
        + *   
        + *     
        + *   
        + * 
        + * + * TODO: + * -- possibly refactor since this is almost the same as TaskDefTask + * (right now these are just too simple to really justify creating an abstract class) + * + * @author Hans Lellelid + * @version $Revision: 1.7 $ + * @package phing.tasks.system + */ +class TypedefTask extends Task { + + /** Tag name for datatype that will be used in XML */ + private $name; + + /** + * Classname of task to register. + * This can be a dot-path -- relative to a location on PHP include_path. + * E.g. path.to.MyClass -> path/to/MyClass.php + * @var string + */ + private $classname; + + /** + * Path to add to PHP include_path to aid in finding specified class. + * @var Path + */ + private $classpath; + + /** Refid to already defined classpath */ + private $classpathId; + + /** + * Set the classpath to be used when searching for component being defined + * + * @param Path $classpath An Path object containing the classpath. + */ + public function setClasspath(Path $classpath) { + if ($this->classpath === null) { + $this->classpath = $classpath; + } else { + $this->classpath->append($classpath); + } + } + + /** + * Create the classpath to be used when searching for component being defined + */ + public function createClasspath() { + if ($this->classpath === null) { + $this->classpath = new Path($this->project); + } + return $this->classpath->createPath(); + } + + /** + * Reference to a classpath to use when loading the files. + */ + public function setClasspathRef(Reference $r) { + $this->classpathId = $r->getRefId(); + $this->createClasspath()->setRefid($r); + } + + /** Main entry point */ + public function main() { + if ($this->name === null || $this->classname === null) { + throw new BuildException("You must specify name and class attributes for ."); + } + $this->project->addDataTypeDefinition($this->name, $this->classname, $this->classpath); + } + + /** + * Sets the name that will be used in XML buildfile. + * @param string $name + */ + public function setName($name) { + $this->name = $name; + } + + /** + * Sets the class name / dotpath to use. + * @param string $class + */ + public function setClassname($class) { + $this->classname = $class; + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/UpToDateTask.php b/buildscripts/phing/classes/phing/tasks/system/UpToDateTask.php new file mode 100644 index 00000000..720fae12 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/UpToDateTask.php @@ -0,0 +1,217 @@ +. + */ + +require_once 'phing/Task.php'; +include_once 'phing/tasks/system/condition/Condition.php'; +include_once 'phing/util/DirectoryScanner.php'; +include_once 'phing/util/SourceFileScanner.php'; +include_once 'phing/mappers/MergeMapper.php'; + +/** + * Sets the given property if the specified target has a timestamp + * greater than all of the source files. + * + * @author Hans Lellelid (Phing) + * @author William Ferguson (Ant) + * @author Hiroaki Nakamura (Ant) + * @author Stefan Bodewig (Ant) + * @version $Revision: 1.6 $ + * @package phing.tasks.system + */ +class UpToDateTask extends Task implements Condition { + + private $_property; + private $_value; + private $_sourceFile; + private $_targetFile; + private $sourceFileSets = array(); + + protected $mapperElement = null; + + /** + * The property to set if the target file is more up-to-date than + * (each of) the source file(s). + * + * @param property the name of the property to set if Target is up-to-date. + */ + public function setProperty($property) { + $this->_property = $property; + } + + /** + * The value to set the named property to if the target file is more + * up-to-date than (each of) the source file(s). Defaults to 'true'. + * + * @param value the value to set the property to if Target is up-to-date + */ + public function setValue($value) { + $this->_value = $value; + } + + /** + * Returns the value, or "true" if a specific value wasn't provided. + */ + private function getValue() { + return ($this->_value !== null) ? $this->_value : "true"; + } + + /** + * The file which must be more up-to-date than (each of) the source file(s) + * if the property is to be set. + * + * @param file the file we are checking against. + */ + public function setTargetFile($file) { + if (is_string($file)) { + $file = new PhingFile($file); + } + $this->_targetFile = $file; + } + + /** + * The file that must be older than the target file + * if the property is to be set. + * + * @param file the file we are checking against the target file. + */ + public function setSrcfile($file) { + if (is_string($file)) { + $file = new PhingFile($file); + } + $this->_sourceFile = $file; + } + + /** + * Nested element. + */ + public function createSrcfiles() { + $fs = new FileSet(); + $this->sourceFileSets[] = $fs; + return $fs; + } + + /** + * Defines the FileNameMapper to use (nested mapper element). + */ + public function createMapper() { + if ($this->mapperElement !== null) { + throw new BuildException("Cannot define more than one mapper", + $this->location); + } + $this->mapperElement = new Mapper($this->getProject()); + return $this->mapperElement; + } + + /** + * Evaluate (all) target and source file(s) to + * see if the target(s) is/are up-to-date. + * @return boolean + */ + public function evaluate() { + if (count($this->sourceFileSets) === 0 && $this->_sourceFile === null) { + throw new BuildException("At least one srcfile or a nested " + . " element must be set."); + } + + if (count($this->sourceFileSets) > 0 && $this->_sourceFile !== null) { + throw new BuildException("Cannot specify both the srcfile " + . "attribute and a nested " + . "element."); + } + + if ($this->_targetFile === null && $this->mapperElement === null) { + throw new BuildException("The targetfile attribute or a nested " + . "mapper element must be set."); + } + + // if the target file is not there, then it can't be up-to-date + if ($this->_targetFile !== null && !$this->_targetFile->exists()) { + return false; + } + + // if the source file isn't there, throw an exception + if ($this->_sourceFile !== null && !$this->_sourceFile->exists()) { + throw new BuildException($this->_sourceFile->getAbsolutePath() + . " not found."); + } + + $upToDate = true; + for($i=0,$size=count($this->sourceFileSets); $i < $size && $upToDate; $i++) { + $fs = $this->sourceFileSets[$i]; + $ds = $fs->getDirectoryScanner($this->project); + $upToDate = $upToDate && $this->scanDir($fs->getDir($this->project), + $ds->getIncludedFiles()); + } + + if ($this->_sourceFile !== null) { + if ($this->mapperElement === null) { + $upToDate = $upToDate && + ($this->_targetFile->lastModified() >= $this->_sourceFile->lastModified()); + } else { + $sfs = new SourceFileScanner($this); + $upToDate = $upToDate && + count($sfs->restrict($this->_sourceFile->getAbsolutePath(), + null, null, + $this->mapperElement->getImplementation())) === 0; + } + } + return $upToDate; + } + + + /** + * Sets property to true if target file(s) have a more recent timestamp + * than (each of) the corresponding source file(s). + * @throws BuildException + */ + public function main() { + if ($this->_property === null) { + throw new BuildException("property attribute is required.", + $this->location); + } + $upToDate = $this->evaluate(); + if ($upToDate) { + $this->project->setNewProperty($this->_property, $this->getValue()); + if ($this->mapperElement === null) { + $this->log("File \"" . $this->_targetFile->getAbsolutePath() + . "\" is up-to-date.", PROJECT_MSG_VERBOSE); + } else { + $this->log("All target files are up-to-date.", + PROJECT_MSG_VERBOSE); + } + } + } + + protected function scanDir(PhingFile $srcDir, $files) { + $sfs = new SourceFileScanner($this); + $mapper = null; + $dir = $srcDir; + if ($this->mapperElement === null) { + $mm = new MergeMapper(); + $mm->setTo($this->_targetFile->getAbsolutePath()); + $mapper = $mm; + $dir = null; + } else { + $mapper = $this->mapperElement->getImplementation(); + } + return (count($sfs->restrict($files, $srcDir, $dir, $mapper)) === 0); + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/WarnTask.php b/buildscripts/phing/classes/phing/tasks/system/WarnTask.php new file mode 100644 index 00000000..50318e71 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/WarnTask.php @@ -0,0 +1,35 @@ +. + */ + +require_once 'phing/tasks/system/EchoTask.php'; + +/** + * Simple task to echo a warning message (PROJECT_MSG_WARN) to all output devices. + * + * @author Hans Lellelid + * @version $Revision: 1.1 $ $Date: 2006-04-28 10:49:47 -0400 (Fri, 28 Apr 2006) $ + * @package phing.tasks.system + */ +class WarnTask extends EchoTask { + function main() { + $this->log($this->msg, PROJECT_MSG_WARN); + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/XsltTask.php b/buildscripts/phing/classes/phing/tasks/system/XsltTask.php new file mode 100644 index 00000000..0374aa59 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/XsltTask.php @@ -0,0 +1,81 @@ +. + */ + +require_once 'phing/tasks/system/CopyTask.php'; +include_once 'phing/system/io/FileReader.php'; +include_once 'phing/system/io/FileWriter.php'; +include_once 'phing/filters/XsltFilter.php'; + +/** + * Implements an XSLT processing filter while copying files. + * + * This is a shortcut for calling the task with the XSLTFilter used + * in the section. + * + * @author Andreas Aderhold, andi@binarycloud.com + * @version $Revision: 1.8 $ + * @package phing.tasks.system + */ +class XsltTask extends CopyTask { + + /** XSLTFilter object that we use to handle transformation. */ + private $xsltFilter; + + /** Parameters to pass to XSLT procesor. */ + private $parameters = array(); + + /** + * Setup the filterchains w/ XSLTFilter that we will use while copying the files. + */ + function init() { + $xf = new XsltFilter(); + $chain = $this->createFilterChain($this->getProject()); + $chain->addXsltFilter($xf); + $this->xsltFilter = $xf; + } + + /** + * Set any XSLT Param and invoke CopyTask::main() + * @see CopyTask::main() + */ + function main() { + $this->log("Doing XSLT transformation using stylesheet " . $this->xsltFilter->getStyle(), PROJECT_MSG_VERBOSE); + $this->xsltFilter->setParams($this->parameters); + parent::main(); + } + + /** + * Set the stylesheet to use. + * @param PhingFile $style + */ + function setStyle(PhingFile $style) { + $this->xsltFilter->setStyle($style); + } + + /** + * Support nested tags useing XSLTParam class. + * @return XSLTParam + */ + function createParam() { + $num = array_push($this->parameters, new XSLTParam()); + return $this->parameters[$num-1]; + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/AndCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/AndCondition.php new file mode 100644 index 00000000..c16ce499 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/AndCondition.php @@ -0,0 +1,46 @@ +. + */ + +require_once 'phing/tasks/system/condition/ConditionBase.php'; + +/** + * condition container. + * + * Iterates over all conditions and returns false as soon as one + * evaluates to false. + * + * @author Hans Lellelid + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.7 $ + * @package phing.tasks.system.condition + */ +class AndCondition extends ConditionBase implements Condition { + + public function evaluate() { + foreach($this as $c) { // ConditionBase implements IteratorAggregator + if (!$c->evaluate()) { + return false; + } + } + return true; + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/Condition.php b/buildscripts/phing/classes/phing/tasks/system/condition/Condition.php new file mode 100644 index 00000000..73e0c232 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/Condition.php @@ -0,0 +1,39 @@ +. + */ + +/** + * Condition interface specification: + * + * Each condition must implement a method applying to this prototye: + * + * @author Hans Lellelid + * @version $Revision: 1.4 $ + * @package phing.tasks.system.condition + */ +interface Condition { + /** + * @return boolean + * @throws BuildException + */ + public function evaluate(); +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/ConditionBase.php b/buildscripts/phing/classes/phing/tasks/system/condition/ConditionBase.php new file mode 100644 index 00000000..1c09fe49 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/ConditionBase.php @@ -0,0 +1,195 @@ +. + */ + +require_once 'phing/ProjectComponent.php'; +include_once 'phing/Project.php'; +include_once 'phing/tasks/system/AvailableTask.php'; +include_once 'phing/tasks/system/condition/Condition.php'; + +/** + * Abstract baseclass for the task as well as several + * conditions - ensures that the types of conditions inside the task + * and the "container" conditions are in sync. + * + * @author Hans Lellelid + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.16 $ + * @package phing.tasks.system.condition + */ +abstract class ConditionBase extends ProjectComponent implements IteratorAggregate { + + public $conditions = array(); // needs to be public for "inner" class access + + function countConditions() { + return count($this->conditions); + } + + /** + * Required for IteratorAggregate + */ + function getIterator() { + return new ConditionEnumeration($this); + } + + function getConditions() { + return $this->conditions; + } + + /** + * @return void + */ + function addAvailable(AvailableTask $a) { + $this->conditions[] = $a; + } + + /** + * @return NotCondition + */ + function createNot() { + include_once 'phing/tasks/system/condition/NotCondition.php'; + $num = array_push($this->conditions, new NotCondition()); + return $this->conditions[$num-1]; + } + + /** + * @return AndCondition + */ + function createAnd() { + include_once 'phing/tasks/system/condition/AndCondition.php'; + $num = array_push($this->conditions, new AndCondition()); + return $this->conditions[$num-1]; + } + + /** + * @return OrCondition + */ + function createOr() { + include_once 'phing/tasks/system/condition/OrCondition.php'; + $num = array_push($this->conditions, new OrCondition()); + return $this->conditions[$num-1]; + } + + /** + * @return EqualsCondition + */ + function createEquals() { + include_once 'phing/tasks/system/condition/EqualsCondition.php'; + $num = array_push($this->conditions, new EqualsCondition()); + return $this->conditions[$num-1]; + } + + /** + * @return OsCondition + */ + function createOs() { + include_once 'phing/tasks/system/condition/OsCondition.php'; + $num = array_push($this->conditions, new OsCondition()); + return $this->conditions[$num-1]; + } + + /** + * @return IsFalseCondition + */ + function createIsFalse() { + include_once 'phing/tasks/system/condition/IsFalseCondition.php'; + $num = array_push($this->conditions, new IsFalseCondition()); + return $this->conditions[$num-1]; + } + + /** + * @return IsTrueCondition + */ + function createIsTrue() { + include_once 'phing/tasks/system/condition/IsTrueCondition.php'; + $num = array_push($this->conditions, new IsTrueCondition()); + return $this->conditions[$num-1]; + } + + /** + * @return ContainsCondition + */ + function createContains() { + include_once 'phing/tasks/system/condition/ContainsCondition.php'; + $num = array_push($this->conditions, new ContainsCondition()); + return $this->conditions[$num-1]; + } + + /** + * @return IsSetCondition + */ + function createIsSet() { + include_once 'phing/tasks/system/condition/IsSetCondition.php'; + $num = array_push($this->conditions, new IsSetCondition()); + return $this->conditions[$num-1]; + } + + /** + * @return ReferenceExistsCondition + */ + function createReferenceExists() { + include_once 'phing/tasks/system/condition/ReferenceExistsCondition.php'; + $num = array_push($this->conditions, new ReferenceExistsCondition()); + return $this->conditions[$num-1]; + } + +} + +/** + * "Inner" class for handling enumerations. + * Uses build-in PHP5 iterator support. + */ +class ConditionEnumeration implements Iterator { + + /** Current element number */ + private $num = 0; + + /** "Outer" ConditionBase class. */ + private $outer; + + function __construct(ConditionBase $outer) { + $this->outer = $outer; + } + + public function valid() { + return $this->outer->countConditions() > $this->num; + } + + function current() { + $o = $this->outer->conditions[$this->num]; + if ($o instanceof ProjectComponent) { + $o->setProject($this->outer->getProject()); + } + return $o; + } + + function next() { + $this->num++; + } + + function key() { + return $this->num; + } + + function rewind() { + $this->num = 0; + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/ContainsCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/ContainsCondition.php new file mode 100644 index 00000000..95849cd8 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/ContainsCondition.php @@ -0,0 +1,76 @@ +. + */ + +require_once 'phing/tasks/system/condition/Condition.php'; + +/** + * Is one string part of another string? + * + * @author Hans Lellelid (Phing) + * @author Stefan Bodewig (Ant) + * @version $Revision: 1.3 $ + * @package phing.tasks.system.condition + */ +class ContainsCondition implements Condition { + + private $string; + private $subString; + private $caseSensitive = true; + + /** + * The string to search in. + * @param string $a1 + */ + public function setString($a1) { + $this->string = $a1; + } + + /** + * The string to search for. + * @param string $a2 + */ + public function setSubstring($a2) { + $this->subString = $a2; + } + + /** + * Whether to search ignoring case or not. + */ + public function setCaseSensitive($b) { + $this->caseSensitive = (boolean) $b; + } + + /** + * Check whether string contains substring. + * @throws BuildException + */ + public function evaluate() { + if ($this->string === null || $this->subString === null) { + throw new BuildException("both string and substring are required " + . "in contains"); + } + + return $this->caseSensitive + ? strpos($this->string, $this->subString) !== false + : substr(strtolower($this->string), strtolower($this->subString)) !== false; + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/EqualsCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/EqualsCondition.php new file mode 100644 index 00000000..32d51380 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/EqualsCondition.php @@ -0,0 +1,78 @@ +. + */ + +require_once 'phing/tasks/system/condition/Condition.php'; + +/** + * A simple string comparator. Compares two strings for eqiality in a + * binary safe manner. Implements the condition interface specification. + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.7 $ $Date: 2006-04-28 10:49:47 -0400 (Fri, 28 Apr 2006) $ + * @access public + * @package phing.tasks.system.condition + */ +class EqualsCondition implements Condition { + + private $arg1; + private $arg2; + private $trim = false; + private $caseSensitive = true; + + public function setArg1($a1) { + $this->arg1 = $a1; + } + + public function setArg2($a2) { + $this->arg2 = $a2; + } + + /** + * Should we want to trim the arguments before comparing them? + * @param boolean $b + */ + public function setTrim($b) { + $this->trim = (boolean) $b; + } + + /** + * Should the comparison be case sensitive? + * @param boolean $b + */ + public function setCaseSensitive($b) { + $this->caseSensitive = (boolean) $b; + } + + public function evaluate() { + if ($this->arg1 === null || $this->arg2 === null) { + throw new BuildException("Both arg1 and arg2 are required in equals."); + } + + if ($this->trim) { + $this->arg1 = trim($this->arg1); + $this->arg2 = trim($this->arg2); + } + + //print("[comparison] Comparing '".$this->arg1."' and '".$this->arg2."'\n"); + return $this->caseSensitive ? $this->arg1 === $this->arg2 : strtolower($this->arg1) === strtolower($this->arg2); + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/IsFalseCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/IsFalseCondition.php new file mode 100644 index 00000000..ebbd1a3d --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/IsFalseCondition.php @@ -0,0 +1,60 @@ +. + */ + +require_once 'phing/ProjectComponent.php'; +require_once 'phing/tasks/system/condition/Condition.php'; + +/** + * Condition that tests whether a given string evals to false. + * + * @author Hans Lellelid (Phing) + * @author Steve Loughran (Ant) + * @version $Revision: 1.4 $ + * @package phing.tasks.system.condition + */ +class IsFalseCondition extends ProjectComponent implements Condition { + + /** + * what we eval + */ + private $value; + + /** + * Set the value to be tested. + * @param boolean $value + */ + public function setValue($value) { + $this->value = $value; + } + + /** + * return the inverted value; + * @throws BuildException if someone forgot to spec a value + */ + public function evaluate() { + if ($this->value === null) { + throw new BuildException("Nothing to test for falsehood"); + } + return !$this->value; + } + +} + diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/IsSetCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/IsSetCondition.php new file mode 100644 index 00000000..4f81c50f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/IsSetCondition.php @@ -0,0 +1,53 @@ +. + */ + +require_once 'phing/ProjectComponent.php'; +require_once 'phing/tasks/system/condition/Condition.php'; + +/** + * Condition that tests whether a given property has been set. + * + * @author Hans Lellelid (Phing) + * @author Stefan Bodewig (Ant) + * @version $Revision: 1.4 $ + * @package phing.tasks.system.condition + */ +class IsSetCondition extends ProjectComponent implements Condition { + + private $property; + + public function setProperty($p) { + $this->property = $p; + } + + /** + * Check whether property is set. + * @throws BuildException + */ + public function evaluate() { + if ($this->property === null) { + throw new BuildException("No property specified for isset " + . "condition"); + } + return $this->project->getProperty($this->property) !== null; + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/IsTrueCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/IsTrueCondition.php new file mode 100644 index 00000000..4affefc5 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/IsTrueCondition.php @@ -0,0 +1,59 @@ +. + */ + +require_once 'phing/ProjectComponent.php'; +require_once 'phing/tasks/system/condition/Condition.php'; + +/** + * Condition that tests whether a given string evals to true. + * + * @author Hans Lellelid (Phing) + * @author Steve Loughran (Ant) + * @package phing.tasks.system.condition + */ +class IsTrueCondition extends ProjectComponent implements Condition { + + /** + * what we eval + */ + private $value; + + /** + * Set the value to be tested. + * @param boolean $value + */ + public function setValue($value) { + $this->value = $value; + } + + /** + * return the inverted value; + * @throws BuildException if someone forgot to spec a value + */ + public function evaluate() { + if ($this->value === null) { + throw new BuildException("Nothing to test for falsehood"); + } + return $this->value; + } + +} + diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/NotCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/NotCondition.php new file mode 100644 index 00000000..c76ef2b8 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/NotCondition.php @@ -0,0 +1,48 @@ +. + */ + +require_once 'phing/tasks/system/condition/ConditionBase.php'; + +/** + * condition. + * + * Evaluates to true if the single condition nested into it is false + * and vice versa. + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.6 $ $Date: 2006-04-28 10:49:47 -0400 (Fri, 28 Apr 2006) $ + * @access public + * @package phing.tasks.system.condition + */ +class NotCondition extends ConditionBase implements Condition { + + function evaluate() { + if ($this->countConditions() > 1) { + throw new BuildException("You must not nest more than one condition into "); + } + if ($this->countConditions() < 1) { + throw new BuildException("You must nest a condition into "); + } + $conds = $this->getIterator(); + return !$conds->current()->evaluate(); + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/OrCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/OrCondition.php new file mode 100644 index 00000000..778abfd0 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/OrCondition.php @@ -0,0 +1,46 @@ +. + */ + +require_once 'phing/tasks/system/condition/ConditionBase.php'; + +/** + * condition container. + * + * Iterates over all conditions and returns true as soon as one + * evaluates to true. + * + * @author Andreas Aderhold + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.8 $ $Date: 2006-04-28 10:49:47 -0400 (Fri, 28 Apr 2006) $ + * @access public + * @package phing.tasks.system.condition + */ +class OrCondition extends ConditionBase implements Condition { + + function evaluate() { + foreach($this as $c) { // ConditionBase implements IteratorAggregator + if ($c->evaluate()) { + return true; + } + } + return false; + } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/OsCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/OsCondition.php new file mode 100644 index 00000000..d80729e7 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/OsCondition.php @@ -0,0 +1,63 @@ +. + */ + +require_once 'phing/tasks/system/condition/ConditionBase.php'; + +/** + * Condition that tests the OS type. + * + * @author Andreas Aderhold + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version $Revision: 1.8 $ $Date: 2006-04-28 10:49:47 -0400 (Fri, 28 Apr 2006) $ + * @access public + * @package phing.tasks.system.condition + */ +class OsCondition implements Condition { + + private $family; + + function setFamily($f) { + $this->family = strtolower($f); + } + + function evaluate() { + $osName = strtolower(Phing::getProperty("os.name")); + + if ($this->family !== null) { + if ($this->family === "windows") { + return StringHelper::startsWith("win", $osName); + } elseif ($this->family === "mac") { + return (strpos($osName, "mac") !== false || strpos($osName, "darwin") !== false); + } elseif ($this->family === ("unix")) { + return ( + StringHelper::endsWith("ix", $osName) || + StringHelper::endsWith("ux", $osName) || + StringHelper::endsWith("bsd", $osName) || + StringHelper::startsWith("sunos", $osName) || + StringHelper::startsWith("darwin", $osName) + ); + } + throw new BuildException("Don't know how to detect os family '" . $this->family . "'"); + } + return false; + } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/ReferenceExistsCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/ReferenceExistsCondition.php new file mode 100644 index 00000000..04c1cbbd --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/ReferenceExistsCondition.php @@ -0,0 +1,52 @@ +. + */ + +require_once 'phing/ProjectComponent.php'; require_once 'phing/tasks/system/condition/Condition.php'; + +/** + * Condition that tests whether a given reference exists. + * + * @author Matthias Pigulla (Phing) + * @version $Revision: 1.1 $ + * @package phing.tasks.system.condition */ +class ReferenceExistsCondition extends ProjectComponent implements Condition { + + private $refid; + + public function setRef($id) { + $this->refid = (string) $id; + } + + /** + * Check whether the reference exists. + * @throws BuildException + */ + public function evaluate() { + if ($this->refid === null) { + throw new BuildException("No ref attribute specified for reference-exists " + . "condition"); + } + $refs = $this->project->getReferences(); + return isset($refs[$this->refid]); + } + +} + diff --git a/buildscripts/phing/classes/phing/types/AbstractFileSet.php b/buildscripts/phing/classes/phing/types/AbstractFileSet.php new file mode 100644 index 00000000..6d640705 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/AbstractFileSet.php @@ -0,0 +1,570 @@ +. + */ + +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/types/DataType.php'; +include_once 'phing/types/PatternSet.php'; +include_once 'phing/types/selectors/BaseSelector.php'; +include_once 'phing/types/selectors/SelectorContainer.php'; +include_once 'phing/types/selectors/BaseSelectorContainer.php'; + +// Load all of the selectors (not really necessary but +// helps reveal parse errors right away) + +include_once 'phing/types/selectors/AndSelector.php'; +include_once 'phing/types/selectors/ContainsSelector.php'; +include_once 'phing/types/selectors/ContainsRegexpSelector.php'; +include_once 'phing/types/selectors/DateSelector.php'; +include_once 'phing/types/selectors/DependSelector.php'; +include_once 'phing/types/selectors/DepthSelector.php'; +include_once 'phing/types/selectors/ExtendSelector.php'; +include_once 'phing/types/selectors/FilenameSelector.php'; +include_once 'phing/types/selectors/MajoritySelector.php'; +include_once 'phing/types/selectors/NoneSelector.php'; +include_once 'phing/types/selectors/NotSelector.php'; +include_once 'phing/types/selectors/OrSelector.php'; +include_once 'phing/types/selectors/PresentSelector.php'; +include_once 'phing/types/selectors/SizeSelector.php'; +include_once 'phing/types/selectors/TypeSelector.php'; + +include_once 'phing/util/DirectoryScanner.php'; + +/** + * The FileSet class provides methods and properties for accessing + * and managing filesets. It extends ProjectComponent and thus inherits + * all methods and properties (not explicitly declared). See ProjectComponent + * for further detail. + * + * TODO: + * - merge this with patternsets: FileSet extends PatternSet !!! + * requires additional mods to the parsing algo + * [HL] .... not sure if that really makes so much sense. I think + * that perhaps they should use common utility class if there really + * is that much shared functionality + * + * @author Andreas Aderhold + * @author Hans Lellelid + * @version $Revision: 1.15 $ $Date: 2005/05/26 13:10:53 $ + * @see ProjectComponent + * @package phing.types + */ +class AbstractFileSet extends DataType implements SelectorContainer { + + // These vars are public for cloning purposes + + /** + * @var boolean + */ + public $useDefaultExcludes = true; + + /** + * @var PatternSet + */ + public $defaultPatterns; + + public $additionalPatterns = array(); + public $dir; + public $isCaseSensitive = true; + public $selectors = array(); + + function __construct($fileset = null) { + if ($fileset !== null && ($fileset instanceof FileSet)) { + $this->dir = $fileset->dir; + $this->defaultPatterns = $fileset->defaultPatterns; + $this->additionalPatterns = $fileset->additionalPatterns; + $this->useDefaultExcludes = $fileset->useDefaultExcludes; + $this->isCaseSensitive = $fileset->isCaseSensitive; + $this->selectors = $fileset->selectors; + } + $this->defaultPatterns = new PatternSet(); + } + + + /** + * Makes this instance in effect a reference to another PatternSet + * instance. + * You must not set another attribute or nest elements inside + * this element if you make it a reference. + */ + function setRefid(Reference $r) { + if ((isset($this->dir) && !is_null($this->dir)) || $this->defaultPatterns->hasPatterns()) { + throw $this->tooManyAttributes(); + } + if (!empty($this->additionalPatterns)) { + throw $this->noChildrenAllowed(); + } + if (!empty($this->selectors)) { + throw $this->noChildrenAllowed(); + } + parent::setRefid($r); + } + + + function setDir($dir) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + if ($dir instanceof PhingFile) { + $dir = $dir->getPath(); + } + $this->dir = new PhingFile((string) $dir); + } + + + function getDir(Project $p) { + if ($this->isReference()) { + return $this->getRef($p)->getDir($p); + } + return $this->dir; + } + + + function createPatternSet() { + if ($this->isReference()) { + throw $this->noChildrenAllowed(); + } + $num = array_push($this->additionalPatterns, new PatternSet()); + return $this->additionalPatterns[$num-1]; + } + + /** + * add a name entry on the include list + */ + function createInclude() { + if ($this->isReference()) { + throw $this->noChildrenAllowed(); + } + return $this->defaultPatterns->createInclude(); + } + + /** + * add a name entry on the include files list + */ + function createIncludesFile() { + if ($this->isReference()) { + throw $this->noChildrenAllowed(); + } + return $this->defaultPatterns->createIncludesFile(); + } + + /** + * add a name entry on the exclude list + */ + function createExclude() { + if ($this->isReference()) { + throw $this->noChildrenAllowed(); + } + return $this->defaultPatterns->createExclude(); + } + + /** + * add a name entry on the include files list + */ + function createExcludesFile() { + if ($this->isReference()) { + throw $this->noChildrenAllowed(); + return; + } + return $this->defaultPatterns->createExcludesFile(); + } + + /** + * Sets the set of include patterns. Patterns may be separated by a comma + * or a space. + */ + function setIncludes($includes) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + $this->defaultPatterns->setIncludes($includes); + } + + /** + * Sets the set of exclude patterns. Patterns may be separated by a comma + * or a space. + */ + function setExcludes($excludes) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + $this->defaultPatterns->setExcludes($excludes); + } + + /** + * Sets the name of the file containing the includes patterns. + * + * @param $incl The file to fetch the include patterns from. + * @throws BE + */ + function setIncludesfile($incl) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + $this->defaultPatterns->setIncludesfile($incl); + } + + /** + * Sets the name of the file containing the includes patterns. + * + * @param $excl The file to fetch the exclude patterns from. + * @throws BE + */ + function setExcludesfile($excl) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + $this->defaultPatterns->setExcludesfile($excl); + } + + /** + * Sets whether default exclusions should be used or not. + * + * @param $useDefaultExcludes "true"|"on"|"yes" when default exclusions + * should be used, "false"|"off"|"no" when they + * shouldn't be used. + */ + function setDefaultexcludes($useDefaultExcludes) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + $this->useDefaultExcludes = $useDefaultExcludes; + } + + /** + * Sets case sensitivity of the file system + */ + function setCaseSensitive($isCaseSensitive) { + $this->isCaseSensitive = $isCaseSensitive; + } + + /** returns a reference to the dirscanner object belonging to this fileset */ + function getDirectoryScanner(Project $p) { + if ($this->isReference()) { + $o = $this->getRef($p); + return $o->getDirectoryScanner($p); + } + + if ($this->dir === null) { + throw new BuildException("No directory specified for fileset."); + } + if (!$this->dir->exists()) { + throw new BuildException("Directory ".$this->dir->getAbsolutePath()." not found."); + } + if (!$this->dir->isDirectory()) { + throw new BuildException($this->dir->getAbsolutePath()." is not a directory."); + } + $ds = new DirectoryScanner(); + $this->setupDirectoryScanner($ds, $p); + $ds->scan(); + return $ds; + } + + /** feed dirscanner with infos defined by this fileset */ + protected function setupDirectoryScanner(DirectoryScanner $ds, Project $p) { + if ($ds === null) { + throw new Exception("DirectoryScanner cannot be null"); + } + // FIXME - pass dir directly wehn dirscanner supports File + $ds->setBasedir($this->dir->getPath()); + + foreach($this->additionalPatterns as $addPattern) { + $this->defaultPatterns->append($addPattern, $p); + } + + $ds->setIncludes($this->defaultPatterns->getIncludePatterns($p)); + $ds->setExcludes($this->defaultPatterns->getExcludePatterns($p)); + + $p->log("FileSet: Setup file scanner in dir " . $this->dir->__toString() . " with " . $this->defaultPatterns->toString(), PROJECT_MSG_DEBUG); + + if ($ds instanceof SelectorScanner) { + $ds->setSelectors($this->getSelectors($p)); + } + + if ($this->useDefaultExcludes) { + $ds->addDefaultExcludes(); + } + $ds->setCaseSensitive($this->isCaseSensitive); + } + + + /** + * Performs the check for circular references and returns the + * referenced FileSet. + */ + function getRef(Project $p) { + if (!$this->checked) { + $stk = array(); + array_push($stk, $this); + $this->dieOnCircularReference($stk, $p); + } + + $o = $this->ref->getReferencedObject($p); + if (!($o instanceof FileSet)) { + $msg = $this->ref->getRefId()." doesn't denote a fileset"; + throw new BuildException($msg); + } else { + return $o; + } + } + + // SelectorContainer methods + + /** + * Indicates whether there are any selectors here. + * + * @return boolean Whether any selectors are in this container + */ + public function hasSelectors() { + if ($this->isReference() && $this->getProject() !== null) { + return $this->getRef($this->getProject())->hasSelectors(); + } + return !empty($this->selectors); + } + + /** + * Indicates whether there are any patterns here. + * + * @return boolean Whether any patterns are in this container. + */ + public function hasPatterns() { + + if ($this->isReference() && $this->getProject() !== null) { + return $this->getRef($this->getProject())->hasPatterns(); + } + + if ($this->defaultPatterns->hasPatterns($this->getProject())) { + return true; + } + + for($i=0,$size=count($this->additionalPatterns); $i < $size; $i++) { + $ps = $this->additionalPatterns[$i]; + if ($ps->hasPatterns($this->getProject())) { + return true; + } + } + + return false; + } + + /** + * Gives the count of the number of selectors in this container + * + * @return int The number of selectors in this container + */ + public function selectorCount() { + if ($this->isReference() && $this->getProject() !== null) { + try { + return $this->getRef($this->getProject())->selectorCount(); + } catch (Exception $e) { + throw $e; + } + } + return count($this->selectors); + } + + /** + * Returns the set of selectors as an array. + * + * @return an array of selectors in this container + */ + public function getSelectors(Project $p) { + if ($this->isReference()) { + return $this->getRef($p)->getSelectors($p); + } else { + // *copy* selectors + $result = array(); + for($i=0,$size=count($this->selectors); $i < $size; $i++) { + $result[] = clone $this->selectors[$i]; + } + return $result; + } + } + + /** + * Returns an array for accessing the set of selectors. + * + * @return array The array of selectors + */ + public function selectorElements() { + if ($this->isReference() && $this->getProject() !== null) { + return $this->getRef($this->getProject())->selectorElements(); + } + return $this->selectors; + } + + /** + * Add a new selector into this container. + * + * @param selector the new selector to add + */ + public function appendSelector(FileSelector $selector) { + if ($this->isReference()) { + throw $this->noChildrenAllowed(); + } + $this->selectors[] = $selector; + } + + /* Methods below all add specific selectors */ + + /** + * add a "Select" selector entry on the selector list + */ + public function createSelector() { + $o = new SelectSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add an "And" selector entry on the selector list + */ + public function createAnd() { + $o = new AndSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add an "Or" selector entry on the selector list + */ + public function createOr() { + $o = new OrSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a "Not" selector entry on the selector list + */ + public function createNot() { + $o = new NotSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a "None" selector entry on the selector list + */ + public function createNone() { + $o = new NoneSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a majority selector entry on the selector list + */ + public function createMajority() { + $o = new MajoritySelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a selector date entry on the selector list + */ + public function createDate() { + $o = new DateSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a selector size entry on the selector list + */ + public function createSize() { + $o = new SizeSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a selector filename entry on the selector list + */ + public function createFilename() { + $o = new FilenameSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add an extended selector entry on the selector list + */ + public function createCustom() { + $o = new ExtendSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a contains selector entry on the selector list + */ + public function createContains() { + $o = new ContainsSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a contains selector entry on the selector list + */ + public function createContainsRegexp() { + $o = new ContainsRegexpSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a present selector entry on the selector list + */ + public function createPresent() { + $o = new PresentSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a depth selector entry on the selector list + */ + public function createDepth() { + $o = new DepthSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a depends selector entry on the selector list + */ + public function createDepend() { + $o = new DependSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a type selector entry on the selector list + */ + public function createType() { + $o = new TypeSelector(); + $this->appendSelector($o); + return $o; + } +} diff --git a/buildscripts/phing/classes/phing/types/Commandline.php b/buildscripts/phing/classes/phing/types/Commandline.php new file mode 100644 index 00000000..877179d0 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/Commandline.php @@ -0,0 +1,467 @@ +. + */ + + +/** + * Commandline objects help handling command lines specifying processes to + * execute. + * + * The class can be used to define a command line as nested elements or as a + * helper to define a command line by an application. + *

        + * + * <someelement>
        + *   <acommandline executable="/executable/to/run">
        + *     <argument value="argument 1" />
        + *     <argument line="argument_1 argument_2 argument_3" />
        + *     <argument value="argument 4" />
        + *   </acommandline>
        + * </someelement>
        + *
        + * The element someelement must provide a method + * createAcommandline which returns an instance of this class. + * + * @author thomas.haas@softwired-inc.com + * @author Stefan Bodewig + */ +class Commandline { + + /** + * @var array CommandlineArguments[] + */ + public $arguments = array(); // public so "inner" class can access + + /** + * Full path (if not on %PATH% env var) to executable program. + * @var string + */ + public $executable; // public so "inner" class can access + + const DISCLAIMER = "The ' characters around the executable and arguments are not part of the command."; + + public function __construct($to_process = null) { + if ($to_process !== null) { + $tmp = $this->translateCommandline($to_process); + if ($tmp) { + $this->setExecutable(array_shift($tmp)); // removes first el + foreach($tmp as $arg) { // iterate through remaining elements + $this->createArgument()->setValue($arg); + } + } + } + } + + + /** + * Creates an argument object and adds it to our list of args. + * + *

        Each commandline object has at most one instance of the + * argument class.

        + * + * @param boolean $insertAtStart if true, the argument is inserted at the + * beginning of the list of args, otherwise it is appended. + * @return CommandlineArgument + */ + public function createArgument($insertAtStart = false) { + $argument = new CommandlineArgument($this); + if ($insertAtStart) { + array_unshift($this->arguments, $argument); + } else { + array_push($this->arguments, $argument); + } + return $argument; + } + + /** + * Sets the executable to run. + */ + public function setExecutable($executable) { + if (!$executable) { + return; + } + $this->executable = $executable; + $this->executable = strtr($this->executable, '/', DIRECTORY_SEPARATOR); + $this->executable = strtr($this->executable, '\\', DIRECTORY_SEPARATOR); + } + + public function getExecutable() { + return $this->executable; + } + + public function addArguments($line) { + foreach($line as $arg) { + $this->createArgument()->setValue($arg); + } + } + + /** + * Returns the executable and all defined arguments. + * @return array + */ + public function getCommandline() { + $args = $this->getArguments(); + if ($this->executable === null) { + return $args; + } + return array_merge(array($this->executable), $args); + } + + + /** + * Returns all arguments defined by addLine, + * addValue or the argument object. + */ + public function getArguments() { + $result = array(); + foreach($this->arguments as $arg) { + $parts = $arg->getParts(); + if ($parts !== null) { + foreach($parts as $part) { + $result[] = $part; + } + } + } + return $result; + } + + public function __toString() { + return self::toString($this->getCommandline()); + } + + /** + * Put quotes around the given String if necessary. + * + *

        If the argument doesn't include spaces or quotes, return it + * as is. If it contains double quotes, use single quotes - else + * surround the argument by double quotes.

        + * + * @exception BuildException if the argument contains both, single + * and double quotes. + */ + public static function quoteArgument($argument) { + if (strpos($argument, "\"") !== false) { + if (strpos($argument, "'") !== false) { + throw new BuildException("Can't handle single and double quotes in same argument"); + } else { + return escapeshellarg($argument); + } + } elseif (strpos($argument, "'") !== false || strpos($argument, " ") !== false) { + return escapeshellarg($argument); + //return '\"' . $argument . '\"'; + } else { + return $argument; + } + } + + /** + * Quotes the parts of the given array in way that makes them + * usable as command line arguments. + */ + public static function toString($lines) { + // empty path return empty string + if (!$lines) { + return ""; + } + + // path containing one or more elements + $result = ""; + for ($i = 0, $len=count($lines); $i < $len; $i++) { + if ($i > 0) { + $result .= ' '; + } + $result .= self::quoteArgument($lines[$i]); + } + return $result; + } + + /** + * + * @param string $to_process + * @return array + */ + public static function translateCommandline($to_process) { + + if (!$to_process) { + return array(); + } + + // parse with a simple finite state machine + + $normal = 0; + $inQuote = 1; + $inDoubleQuote = 2; + + $state = $normal; + $args = array(); + $current = ""; + $lastTokenHasBeenQuoted = false; + + $tok = strtok($to_process, ""); + $tokens = preg_split('/(["\' ])/', $to_process, -1, PREG_SPLIT_DELIM_CAPTURE); + while(($nextTok = array_shift($tokens)) !== null) { + switch ($state) { + case $inQuote: + if ("'" == $nextTok) { + $lastTokenHasBeenQuoted = true; + $state = $normal; + } else { + $current .= $nextTok; + } + break; + case $inDoubleQuote: + if ("\"" == $nextTok) { + $lastTokenHasBeenQuoted = true; + $state = $normal; + } else { + $current .= $nextTok; + } + break; + default: + if ("'" == $nextTok) { + $state = $inQuote; + } elseif ("\"" == $nextTok) { + $state = $inDoubleQuote; + } elseif (" " == $nextTok) { + if ($lastTokenHasBeenQuoted || strlen($current) != 0) { + $args[] = $current; + $current = ""; + } + } else { + $current .= $nextTok; + } + $lastTokenHasBeenQuoted = false; + break; + } + } + + if ($lastTokenHasBeenQuoted || strlen($current) != 0) { + $args[] = $current; + } + + if ($state == $inQuote || $state == $inDoubleQuote) { + throw new BuildException("unbalanced quotes in " . $to_process); + } + + return $args; + } + + /** + * @return int Number of components in current commandline. + */ + public function size() { + return count($this->getCommandline()); + } + + public function __copy() { + $c = new Commandline(); + $c->setExecutable($this->executable); + $c->addArguments($this->getArguments()); + return $c; + } + + /** + * Clear out the whole command line. */ + public function clear() { + $this->executable = null; + $this->arguments->removeAllElements(); + } + + /** + * Clear out the arguments but leave the executable in place for + * another operation. + */ + public function clearArgs() { + $this->arguments = array(); + } + + /** + * Return a marker. + * + *

        This marker can be used to locate a position on the + * commandline - to insert something for example - when all + * parameters have been set.

        + * @return CommandlineMarker + */ + public function createMarker() { + return new CommandlineMarker($this, count($this->arguments)); + } + + /** + * Returns a String that describes the command and arguments + * suitable for verbose output before a call to + * Runtime.exec(String[]). + * + *

        This method assumes that the first entry in the array is the + * executable to run.

        + * @param array $args CommandlineArgument[] to use + * @return string + */ + public function describeCommand($args = null) { + + if ($args === null) { + $args = $this->getCommandline(); + } + + if (!$args) { + return ""; + } + + $buf = "Executing '"; + $buf .= $args[0]; + $buf .= "'"; + if (count($args) > 0) { + $buf .= " with "; + $buf .= $this->describeArguments($args, 1); + } else { + $buf .= self::DISCLAIMER; + } + return $buf; + } + + /** + * Returns a String that describes the arguments suitable for + * verbose output before a call to + * Runtime.exec(String[]) + * @param $args arguments to use (default is to use current class args) + * @param $offset ignore entries before this index + * @return string + */ + protected function describeArguments($args = null, $offset = 0) { + if ($args === null) { + $args = $this->getArguments(); + } + + if ($args === null || count($args) <= $offset) { + return ""; + } + + $buf = "argument"; + if (count($args) > $offset) { + $buf .= "s"; + } + $buf .= ":" . Phing::getProperty("line.separator"); + for ($i = $offset, $alen=count($args); $i < $alen; $i++) { + $buf .= "'" . $args[$i] . "'" . Phing::getProperty("line.separator"); + } + $buf .= self::DISCLAIMER; + return $buf; + } +} + + +/** + * "Inner" class used for nested xml command line definitions. + */ +class CommandlineArgument { + + private $parts = array(); + private $outer; + + public function __construct(Commandline $outer) { + $this->outer = $outer; + } + + /** + * Sets a single commandline argument. + * + * @param string $value a single commandline argument. + */ + public function setValue($value) { + $this->parts = array($value); + } + + /** + * Line to split into several commandline arguments. + * + * @param line line to split into several commandline arguments + */ + public function setLine($line) { + if ($line === null) { + return; + } + $this->parts = $this->outer->translateCommandline($line); + } + + /** + * Sets a single commandline argument and treats it like a + * PATH - ensures the right separator for the local platform + * is used. + * + * @param value a single commandline argument. + */ + public function setPath($value) { + $this->parts = array( (string) $value ); + } + + /** + * Sets a single commandline argument to the absolute filename + * of the given file. + * + * @param value a single commandline argument. + */ + public function setFile(PhingFile $value) { + $this->parts = array($value->getAbsolutePath()); + } + + /** + * Returns the parts this Argument consists of. + * @return array string[] + */ + public function getParts() { + return $this->parts; + } +} + +/** + * Class to keep track of the position of an Argument. + */ +//

        This class is there to support the srcfile and targetfile +// elements of <execon> and <transform> - don't know +// whether there might be additional use cases.

        --SB +class CommandlineMarker { + + private $position; + private $realPos = -1; + private $outer; + + public function __construct(Comandline $outer, $position) { + $this->outer = $outer; + $this->position = $position; + } + + /** + * Return the number of arguments that preceeded this marker. + * + *

        The name of the executable - if set - is counted as the + * very first argument.

        + */ + public function getPosition() { + if ($this->realPos == -1) { + $realPos = ($this->outer->executable === null ? 0 : 1); + for ($i = 0; $i < $position; $i++) { + $arg = $this->arguments[$i]; + $realPos += count($arg->getParts()); + } + } + return $this->realPos; + } +} + diff --git a/buildscripts/phing/classes/phing/types/DataType.php b/buildscripts/phing/classes/phing/types/DataType.php new file mode 100644 index 00000000..2c06b80d --- /dev/null +++ b/buildscripts/phing/classes/phing/types/DataType.php @@ -0,0 +1,182 @@ +. + */ + +require_once 'phing/ProjectComponent.php'; +include_once 'phing/BuildException.php'; + +/** + * Base class for those classes that can appear inside the build file + * as stand alone data types. + * + * This class handles the common description attribute and provides + * a default implementation for reference handling and checking for + * circular references that is appropriate for types that can not be + * nested inside elements of the same type (i.e. patternset but not path) + * + * @package phing.types + */ +class DataType extends ProjectComponent { + + /** The descriptin the user has set. */ + public $description = null; + + /** Value to the refid attribute. Type of Reference*/ + public $ref = null; + + /** + * Are we sure we don't hold circular references? + * + * Subclasses are responsible for setting this value to false + * if we'd need to investigate this condition (usually because a + * child element has been added that is a subclass of DataType). + * @var boolean + */ + protected $checked = true; + + /** + * Sets a description of the current data type. It will be useful + * in commenting what we are doing. + */ + function setDescription($desc) { + $this->description = (string) $desc; + } + + /** Return the description for the current data type. */ + function getDescription() { + return $this->description; + } + + /** Has the refid attribute of this element been set? */ + function isReference() { + return ($this->ref !== null); + } + + /** + * Set the value of the refid attribute. + * + * Subclasses may need to check whether any other attributes + * have been set as well or child elements have been created and + * thus override this method. if they do they must call parent::setRefid() + * + * @param Reference $r + * @return void + */ + function setRefid(Reference $r) { + $this->ref = $r; + $this->checked = false; + } + + /** + * Check to see whether any DataType we hold references to is + * included in the Stack (which holds all DataType instances that + * directly or indirectly reference this instance, including this + * instance itself). + * + * If one is included, throw a BuildException created by circularReference + * + * This implementation is appropriate only for a DataType that + * cannot hold other DataTypes as children. + * + * The general contract of this method is that it shouldn't do + * anything if checked is true and set it to true on exit. + */ + function dieOnCircularReference(&$stk, Project $p) { + if ($this->checked || !$this->isReference()) { + return; + } + + $o = $this->ref->getReferencedObject($p); + + if ($o instanceof DataType) { + + // TESTME - make sure that in_array() works just as well here + // + // check if reference is in stack + //$contains = false; + //for ($i=0, $size=count($stk); $i < $size; $i++) { + // if ($stk[$i] === $o) { + // $contains = true; + // break; + // } + //} + + if (in_array($o, $stk, true)) { + // throw build exception + throw $this->circularReference(); + } else { + array_push($stk, $o); + $o->dieOnCircularReference($stk, $p); + array_pop($stk); + } + } + $this->checked = true; + } + + /** Performs the check for circular references and returns the referenced object. */ + function getCheckedRef($requiredClass, $dataTypeName) { + + if (!$this->checked) { + // should be in stack + $stk = array(); + $stk[] = $this; + $this->dieOnCircularReference($stk, $this->getProject()); + } + + $o = $this->ref->getReferencedObject($this->getProject()); + if (!($o instanceof $requiredClass) ) { + throw new BuildException($this->ref->getRefId()." doesn't denote a " . $dataTypeName); + } else { + return $o; + } + } + + /** + * Creates an exception that indicates that refid has to be the + * only attribute if it is set. + */ + function tooManyAttributes() { + return new BuildException( "You must not specify more than one attribute when using refid" ); + } + + /** + * Creates an exception that indicates that this XML element must + * not have child elements if the refid attribute is set. + */ + function noChildrenAllowed() { + return new BuildException("You must not specify nested elements when using refid"); + } + + /** + * Creates an exception that indicates the user has generated a + * loop of data types referencing each other. + */ + function circularReference() { + return new BuildException("This data type contains a circular reference."); + } + + /** + * Template method being called when the data type has been + * parsed completely. + * @return void + */ + function parsingComplete() {} +} + diff --git a/buildscripts/phing/classes/phing/types/Description.php b/buildscripts/phing/classes/phing/types/Description.php new file mode 100644 index 00000000..e69f8da4 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/Description.php @@ -0,0 +1,53 @@ +. + */ + +/** + * Description is used to provide a project-wide description element + * (that is, a description that applies to a buildfile as a whole). + * If present, the <description> element is printed out before the + * target descriptions. + * + * Description has no attributes, only text. There can only be one + * project description per project. A second description element will + * overwrite the first. + * + * @author Hans Lellelid (Phing) + * @author Craeg Strong (Ant) + * @package phing.types + */ +class Description extends DataType { + + /** + * Adds descriptive text to the project. + * + * @return void + */ + public function addText($text) { + $currentDescription = $this->project->getDescription(); + if ($currentDescription === null) { + $this->project->setDescription($text); + } else { + $this->project->setDescription($currentDescription . $text); + } + } + +} diff --git a/buildscripts/phing/classes/phing/types/DirSet.php b/buildscripts/phing/classes/phing/types/DirSet.php new file mode 100644 index 00000000..45bcc636 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/DirSet.php @@ -0,0 +1,49 @@ +. + */ + +include_once 'phing/types/AbstractFileSet.php'; + +/** + * Subclass as hint for supporting tasks that the included directories + * instead of files should be used. + * + * @package phing.types + */ +class DirSet extends AbstractFileSet { + + public function __construct($dirset = null) { + parent::__construct($dirset); + } + + /** + * Return a DirSet that has the same basedir and same patternsets + * as this one. + */ + public function __clone() { + if ($this->isReference()) { + return new DirSet($this->getRef($this->getProject())); + } else { + return new DirSet($this); + } + } + +} diff --git a/buildscripts/phing/classes/phing/types/FileList.php b/buildscripts/phing/classes/phing/types/FileList.php new file mode 100644 index 00000000..1ec1273f --- /dev/null +++ b/buildscripts/phing/classes/phing/types/FileList.php @@ -0,0 +1,223 @@ +. + */ + +require_once 'phing/types/DataType.php'; +include_once 'phing/system/io/PhingFile.php'; + +/** + * FileList represents an explicitly named list of files. FileLists + * are useful when you want to capture a list of files regardless of + * whether they currently exist. + * + * + * + * OR + * + * + * + * (or a mixture of files="" and listfile="" can be used) + * + * @author Hans Lellelid + * @version $Revision: 1.10 $ + * @package phing.types + */ +class FileList extends DataType { + + // public for "cloning" purposes + + /** Array containing all filenames. */ + public $filenames = array(); + + /** Base directory for this file list. */ + public $dir; + + /** PhingFile that contains a list of files (one per line). */ + public $listfile; + + /** + * Construct a new FileList. + * @param array $filelist; + */ + function __construct($filelist = null) { + if ($filelist !== null) { + $this->dir = $filelist->dir; + $this->filenames = $filelist->filenames; + $this->listfile = $filelist->listfile; + } + } + + /** + * Makes this instance in effect a reference to another FileList + * instance. + */ + function setRefid(Reference $r) { + if ($this->dir !== null || count($this->filenames) !== 0) { + throw $this->tooManyAttributes(); + } + parent::setRefid($r); + } + + /** + * Base directory for files in list. + * @param PhingFile $dir + */ + function setDir(PhingFile $dir) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + if (!($dir instanceof PhingFile)) { + $dir = new PhingFile($dir); + } + $this->dir = $dir; + } + + /** + * Get the basedir for files in list. + * @return PhingFile + */ + function getDir(Project $p) { + if ($this->isReference()) { + $ref = $this->getRef($p); + return $ref->getDir($p); + } + return $this->dir; + } + + /** + * Set the array of files in list. + * @param array $filenames + */ + function setFiles($filenames) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + if (!empty($filenames)) { + $tok = strtok($filenames, ", \t\n\r"); + while ($tok !== false) { + $fname = trim($tok); + if ($fname !== "") { + $this->filenames[] = $tok; + } + $tok = strtok(", \t\n\r"); + } + } + } + + /** + * Sets a source "list" file that contains filenames to add -- one per line. + * @param string $file + */ + function setListFile($file) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + if (!($file instanceof PhingFile)) { + $file = new PhingFile($file); + } + $this->listfile = $file; + } + + /** + * Get the source "list" file that contains file names. + * @return PhingFile + */ + function getListFile() { + if ($this->isReference()) { + $ref = $this->getRef($p); + return $ref->getListFile($p); + } + return $this->listfile; + } + + /** + * Returns the list of files represented by this FileList. + * @param Project $p + * @return array + */ + function getFiles(Project $p) { + + if ($this->isReference()) { + $ret = $this->getRef($p); + $ret = $ret->getFiles($p); + return $ret; + } + + if ($this->listfile !== null) { + $this->readListFile($p); + } + + return $this->filenames; + } + + + /** + * Performs the check for circular references and returns the + * referenced FileSet. + * @param Project $p + */ + function getRef(Project $p) { + if (!$this->checked) { + $stk = array(); + array_push($stk, $this); + $this->dieOnCircularReference($stk, $p); + } + + $o = $this->ref->getReferencedObject($p); + if (!($o instanceof FileList)) { + throw new BuildException($this->ref->getRefId()." doesn't denote a filelist"); + } else { + return $o; + } + } + + /** + * Reads file names from a file and adds them to the files array. + * @param Project $p + */ + private function readListFile(Project $p) { + $listReader = null; + try { + // Get a FileReader + $listReader = new BufferedReader(new FileReader($this->listfile)); + + $line = $listReader->readLine(); + while ($line !== null) { + if (!empty($line)) { + $line = $p->replaceProperties($line); + $this->filenames[] = trim($line); + } + $line = $listReader->readLine(); + } + } catch (Exception $e) { + if ($listReader) $listReader->close(); + throw new BuildException("An error occured while reading from list file " . $this->listfile->__toString() . ": " . $e->getMessage()); + } + + $listReader->close(); + } + +} + diff --git a/buildscripts/phing/classes/phing/types/FileSet.php b/buildscripts/phing/classes/phing/types/FileSet.php new file mode 100644 index 00000000..8cfb54dc --- /dev/null +++ b/buildscripts/phing/classes/phing/types/FileSet.php @@ -0,0 +1,56 @@ +. + */ + +require_once 'phing/types/AbstractFileSet.php'; + +/** + * Moved out of MatchingTask to make it a standalone object that could + * be referenced (by scripts for example). + * + * @author Hans Lellelid (Phing) + * @author Arnout J. Kuiper (Ant) + * @author Stefano Mazzocchi (Ant) + * @author Sam Ruby (Ant) + * @author Jon S. Stevens (Ant) + * @author Stefan Bodewig (Ant) + * @author Magesh Umasankar (Ant) + * @package phing.types + */ +class FileSet extends AbstractFileSet { + + function __construct($fileset = null) { + parent::__construct($fileset); + } + + /** + * Return a FileSet that has the same basedir and same patternsets + * as this one. + */ + public function __clone() { + if ($this->isReference()) { + return new FileSet($this->getRef($this->getProject())); + } else { + return new FileSet($this); + } + } + +} diff --git a/buildscripts/phing/classes/phing/types/FilterChain.php b/buildscripts/phing/classes/phing/types/FilterChain.php new file mode 100644 index 00000000..4f2d702b --- /dev/null +++ b/buildscripts/phing/classes/phing/types/FilterChain.php @@ -0,0 +1,164 @@ +. + */ + +include_once 'phing/types/DataType.php'; +include_once 'phing/filters/HeadFilter.php'; +include_once 'phing/filters/TailFilter.php'; +include_once 'phing/filters/LineContains.php'; +include_once 'phing/filters/LineContainsRegexp.php'; +include_once 'phing/filters/ExpandProperties.php'; +include_once 'phing/filters/PrefixLines.php'; +include_once 'phing/filters/ReplaceRegexp.php'; +include_once 'phing/filters/ReplaceTokens.php'; +include_once 'phing/filters/StripPhpComments.php'; +include_once 'phing/filters/StripLineBreaks.php'; +include_once 'phing/filters/StripLineComments.php'; +include_once 'phing/filters/TabToSpaces.php'; +include_once 'phing/filters/TidyFilter.php'; +include_once 'phing/filters/TranslateGettext.php'; +include_once 'phing/filters/XsltFilter.php'; + +/* + * FilterChain may contain a chained set of filter readers. + * + * @author Yannick Lecaillez + * @version $Revision: 1.11 $ + * @package phing.types + */ +class FilterChain extends DataType { + + private $filterReaders = array(); + + function __construct(Project $project) { + $this->project = $project; + } + + function getFilterReaders() { + return $this->filterReaders; + } + + function addExpandProperties(ExpandProperties $o) { + $o->setProject($this->project); + $this->filterReaders[] = $o; + } + + function addGettext(TranslateGettext $o) { + $o->setProject($this->project); + $this->filterReaders[] = $o; + } + + function addHeadFilter(HeadFilter $o) { + $o->setProject($this->project); + $this->filterReaders[] = $o; + } + + function addTailFilter(TailFilter $o) { + $o->setProject($this->project); + $this->filterReaders[] = $o; + } + + function addLineContains(LineContains $o) { + $o->setProject($this->project); + $this->filterReaders[] = $o; + } + + function addLineContainsRegExp(LineContainsRegExp $o) { + $o->setProject($this->project); + $this->filterReaders[] = $o; + } + + function addPrefixLines(PrefixLines $o) { + $o->setProject($this->project); + $this->filterReaders[] = $o; + } + + function addReplaceTokens(ReplaceTokens $o) { + $o->setProject($this->project); + $this->filterReaders[] = $o; + } + + function addReplaceRegexp(ReplaceRegexp $o) { + $o->setProject($this->project); + $this->filterReaders[] = $o; + } + + function addStripPhpComments(StripPhpComments $o) { + $o->setProject($this->project); + $this->filterReaders[] = $o; + } + + function addStripLineBreaks(StripLineBreaks $o) { + $o->setProject($this->project); + $this->filterReaders[] = $o; + } + + function addStripLineComments(StripLineComments $o) { + $o->setProject($this->project); + $this->filterReaders[] = $o; + } + + function addTidyFilter(TidyFilter $o) { + $o->setProject($this->project); + $this->filterReaders[] = $o; + } + + function addTabToSpaces(TabToSpaces $o) { + $o->setProject($this->project); + $this->filterReaders[] = $o; + } + + function addXsltFilter(XsltFilter $o) { + $o->setProject($this->project); + $this->filterReaders[] = $o; + } + + function addFilterReader(PhingFilterReader $o) { + $o->setProject($this->project); + $this->filterReaders[] = $o; + } + + /* + * Makes this instance in effect a reference to another FilterChain + * instance. + * + *

        You must not set another attribute or nest elements inside + * this element if you make it a reference.

        + * + * @param r the reference to which this instance is associated + * @throw BuildException if this instance already has been configured. + */ + function setRefid(Reference $r) { + + if ( count($this->filterReaders) === 0 ) { + throw $this->tooManyAttributes(); + } + + // change this to get the objects from the other reference + $o = $r->getReferencedObject($this->getProject()); + if ( $o instanceof FilterChain ) { + $this->filterReaders = $o->getFilterReaders(); + } else { + throw new BuildException($r->getRefId()." doesn't refer to a FilterChain"); + } + parent::setRefid($r); + } + +} diff --git a/buildscripts/phing/classes/phing/types/Mapper.php b/buildscripts/phing/classes/phing/types/Mapper.php new file mode 100644 index 00000000..f0df6d24 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/Mapper.php @@ -0,0 +1,207 @@ +. + */ + +include_once 'phing/types/DataType.php'; +include_once 'phing/types/Path.php'; + +/** + * Filename Mapper maps source file name(s) to target file name(s). + * + * Built-in mappers can be accessed by specifying they "type" attribute: + * + * + * + * Custom mappers can be specified by providing a dot-path to a include_path-relative + * class: + * + * + * + * + * + * @author Hans Lellelid + * @package phing.types + */ +class Mapper extends DataType { + + protected $type; + protected $classname; + protected $from; + protected $to; + protected $classpath; + protected $classpathId; + + + function __construct(Project $project) { + $this->project = $project; + } + + /** + * Set the classpath to be used when searching for component being defined + * + * @param Path $classpath An Path object containing the classpath. + */ + public function setClasspath(Path $classpath) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + if ($this->classpath === null) { + $this->classpath = $classpath; + } else { + $this->classpath->append($classpath); + } + } + + /** + * Create the classpath to be used when searching for component being defined + */ + public function createClasspath() { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + if ($this->classpath === null) { + $this->classpath = new Path($this->project); + } + return $this->classpath->createPath(); + } + + /** + * Reference to a classpath to use when loading the files. + */ + public function setClasspathRef(Reference $r) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + $this->classpathId = $r->getRefId(); + $this->createClasspath()->setRefid($r); + } + + /** Set the type of FileNameMapper to use. */ + function setType($type) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + $this->type = $type; + } + + /** Set the class name of the FileNameMapper to use. */ + function setClassname($classname) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + $this->classname = $classname; + } + + /** + * Set the argument to FileNameMapper.setFrom + */ + function setFrom($from) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + $this->from = $from; + } + + /** + * Set the argument to FileNameMapper.setTo + */ + function setTo($to) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + $this->to = $to; + } + + /** + * Make this Mapper instance a reference to another Mapper. + * + * You must not set any other attribute if you make it a reference. + */ + function setRefid($r) { + if ($this->type !== null || $this->from !== null || $this->to !== null) { + throw DataType::tooManyAttributes(); + } + parent::setRefid($r); + } + + /** Factory, returns inmplementation of file name mapper as new instance */ + function getImplementation() { + if ($this->isReference()) { + $tmp = $this->getRef(); + return $tmp->getImplementation(); + } + + if ($this->type === null && $this->classname === null) { + throw new BuildException("either type or classname attribute must be set for "); + } + + if ($this->type !== null) { + switch($this->type) { + case 'identity': + $this->classname = 'phing.mappers.IdentityMapper'; + break; + case 'flatten': + $this->classname = 'phing.mappers.FlattenMapper'; + break; + case 'glob': + $this->classname = 'phing.mappers.GlobMapper'; + break; + case 'regexp': + case 'regex': + $this->classname = 'phing.mappers.RegexpMapper'; + break; + case 'merge': + $this->classname = 'phing.mappers.MergeMapper'; + break; + default: + throw new BuildException("Mapper type {$this->type} not known"); + break; + } + } + + // get the implementing class + $cls = Phing::import($this->classname, $this->classpath); + + $m = new $cls; + $m->setFrom($this->from); + $m->setTo($this->to); + + return $m; + } + + /** Performs the check for circular references and returns the referenced Mapper. */ + private function getRef() { + if (!$this->checked) { + $stk = array(); + $stk[] = $this; + $this->dieOnCircularReference($stk, $this->project); + } + + $o = $this->ref->getReferencedObject($this->project); + if (!($o instanceof Mapper)) { + $msg = $this->ref->getRefId()." doesn't denote a mapper"; + throw new BuildException($msg); + } else { + return $o; + } + } +} + +?> diff --git a/buildscripts/phing/classes/phing/types/Parameter.php b/buildscripts/phing/classes/phing/types/Parameter.php new file mode 100644 index 00000000..6892ed7e --- /dev/null +++ b/buildscripts/phing/classes/phing/types/Parameter.php @@ -0,0 +1,99 @@ +. +*/ + +include_once 'phing/types/DataType.php'; + +/* + * A parameter is composed of a name, type and value. Nested + * Parameters are also possible, but the using task/type has + * to support them + * + * @author Manuel Holtgrewe + * @author Yannick Lecaillez + * @package phing.types +*/ +class Parameter extends DataType { + + /** Parameter name */ + protected $name; + + /** Paramter type */ + protected $type; + + /** Parameter value */ + protected $value; + + /** Nested parameters */ + protected $parameters = array(); + + function setName($name) { + $this->name = (string) $name; + } + + function setType($type) { + $this->type = (string) $type; + } + + /** + * Sets value to dynamic register slot. + * @param RegisterSlot $value + */ + public function setListeningValue(RegisterSlot $value) { + $this->value = $value; + } + + function setValue($value) { + $this->value = (string) $value; + } + + function getName() { + return $this->name; + } + + function getType() { + return $this->type; + } + + function getValue() { + if ($this->value instanceof RegisterSlot) { + return $this->value->getValue(); + } else { + return $this->value; + } + } + + /** + * @return Parameter + */ + function createParam() { + $num = array_push($this->parameters, new Parameter()); + return $this->parameters[$num-1]; + } + + /** + * @return array Nested parameters. + */ + function getParams() { + return $this->parameters; + } +} + +?> diff --git a/buildscripts/phing/classes/phing/types/Parameterizable.php b/buildscripts/phing/classes/phing/types/Parameterizable.php new file mode 100644 index 00000000..b24aa38b --- /dev/null +++ b/buildscripts/phing/classes/phing/types/Parameterizable.php @@ -0,0 +1,32 @@ +. + */ + +/** + * Parameterizable objects take genric key value pairs. + * + * @author Hans Lellelid, hans@xmpl.org (Phing) + * @author Magesh Umasankar (Ant) + * @package phing.types + */ +interface Parameterizable { + function setParameters($parameters); +} diff --git a/buildscripts/phing/classes/phing/types/Path.php b/buildscripts/phing/classes/phing/types/Path.php new file mode 100644 index 00000000..196fe9c4 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/Path.php @@ -0,0 +1,456 @@ +. + */ + +require_once 'phing/types/DataType.php'; +include_once 'phing/util/PathTokenizer.php'; +include_once 'phing/types/FileSet.php'; + +/** + * This object represents a path as used by include_path or PATH + * environment variable. + * + * This class has been adopted from the Java Ant equivalent. The ability have + * path structures in Phing is important; however, because of how PHP classes interact + * the ability to specify CLASSPATHs makes less sense than Java.Rather than providing + * CLASSPATH for any tasks that take classes as parameters, perhaps a better + * solution in PHP is to have an IncludePath task, which prepends paths to PHP's include_path + * INI variable. This gets around the problem that simply using a path to load the initial + * PHP class is not enough (in most cases the loaded class may assume that it is on the global + * PHP include_path, and will try to load dependent classes accordingly). The other option is + * to provide a way for this class to add paths to the include path, if desired -- or to create + * an IncludePath subclass. Once added, though, when would a path be removed from the include path? + * + *

        + * + * <sometask>
        + *   <somepath>
        + *     <pathelement location="/path/to/file" />
        + *     <pathelement path="/path/to/class2;/path/to/class3" />
        + *     <pathelement location="/path/to/file3" />
        + *   </somepath>
        + * </sometask>
        + *
        + *

        + * The object implemention sometask must provide a method called + * createSomepath which returns an instance of Path. + * Nested path definitions are handled by the Path object and must be labeled + * pathelement.

        + * + * The path element takes a parameter path which will be parsed + * and split into single elements. It will usually be used + * to define a path from an environment variable. + * + * @author Hans Lellelid (Phing) + * @author Thomas.Haas@softwired-inc.com (Ant) + * @author Stefan Bodewig (Ant) + * @package phing.types + */ +class Path extends DataType { + + private $elements = array(); + + /** + * Constructor for internally instantiated objects sets project. + * @param Project $project + * @param string $path (for use by IntrospectionHelper) + */ + public function __construct($project = null, $path = null) { + if ($project !== null) { + $this->setProject($project); + } + if ($path !== null) { + $this->createPathElement()->setPath($path); + } + } + + /** + * Adds a element definition to the path. + * @param $location the location of the element to add (must not be + * null nor empty. + * @throws BuildException + */ + public function setDir(PhingFile $location) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + $this->createPathElement()->setDir($location); + } + + /** + * Parses a path definition and creates single PathElements. + * @param path the path definition. + * @throws BuildException + */ + public function setPath($path) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + $this->createPathElement()->setPath($path); + } + + /** + * Makes this instance in effect a reference to another Path instance. + * + *

        You must not set another attribute or nest elements inside + * this element if you make it a reference.

        + * @throws BuildException + */ + public function setRefid(Reference $r) { + if (!empty($this->elements)) { + throw $this->tooManyAttributes(); + } + $this->elements[] = $r; + parent::setRefid($r); + } + + /** + * Creates the nested <pathelement> element. + * @throws BuildException + */ + public function createPathElement() { + if ($this->isReference()) { + throw $this->noChildrenAllowed(); + } + $pe = new PathElement($this); + $this->elements[] = $pe; + return $pe; + } + + /** + * Adds a nested <fileset> element. + * @throws BuildException + */ + public function addFileset(FileSet $fs) { + if ($this->isReference()) { + throw $this->noChildrenAllowed(); + } + $this->elements[] = $fs; + $this->checked = false; + } + + /** + * Adds a nested <dirset> element. + * @throws BuildException + */ + public function addDirset(DirSet $dset) { + if ($this->isReference()) { + throw $this->noChildrenAllowed(); + } + $this->elements[] = $dset; + $this->checked = false; + } + + /** + * Creates a nested <path> element. + * @throws BuildException + */ + public function createPath() { + if ($this->isReference()) { + throw $this->noChildrenAllowed(); + } + $p = new Path($this->project); + $this->elements[] = $p; + $this->checked = false; + return $p; + } + + /** + * Append the contents of the other Path instance to this. + */ + public function append(Path $other) { + if ($other === null) { + return; + } + $l = $other->listPaths(); + foreach($l as $path) { + if (!in_array($path, $this->elements, true)) { + $this->elements[] = $path; + } + } + } + + /** + * Adds the components on the given path which exist to this + * Path. Components that don't exist, aren't added. + * + * @param Path $source - Source path whose components are examined for existence. + */ + public function addExisting(Path $source) { + $list = $source->listPaths(); + foreach($list as $el) { + $f = null; + if ($this->project !== null) { + $f = $this->project->resolveFile($el); + } else { + $f = new PhingFile($el); + } + + if ($f->exists()) { + $this->setDir($f); + } else { + $this->log("dropping " . $f->__toString() . " from path as it doesn't exist", + PROJECT_MSG_VERBOSE); + } + } + } + + /** + * Returns all path elements defined by this and nested path objects. + * @return array List of path elements. + */ + public function listPaths() { + if (!$this->checked) { + // make sure we don't have a circular reference here + $stk = array(); + array_push($stk, $this); + $this->dieOnCircularReference($stk, $this->project); + } + + $result = array(); + for ($i = 0, $elSize=count($this->elements); $i < $elSize; $i++) { + $o = $this->elements[$i]; + if ($o instanceof Reference) { + $o = $o->getReferencedObject($this->project); + // we only support references to paths right now + if (!($o instanceof Path)) { + $msg = $r->getRefId() . " doesn't denote a path"; + throw new BuildException($msg); + } + } + + if (is_string($o)) { + $result[] = $o; + } elseif ($o instanceof PathElement) { + $parts = $o->getParts(); + if ($parts === null) { + throw new BuildException("You must either set location or" + . " path on "); + } + foreach($parts as $part) { + $result[] = $part; + } + } elseif ($o instanceof Path) { + $p = $o; + if ($p->getProject() === null) { + $p->setProject($this->getProject()); + } + $parts = $p->listPaths(); + foreach($parts as $part) { + $result[] = $part; + } + } elseif ($o instanceof DirSet) { + $dset = $o; + $ds = $dset->getDirectoryScanner($this->project); + $dirstrs = $ds->getIncludedDirectories(); + $dir = $dset->getDir($this->project); + $this->addUnlessPresent($result, $dir, $s); + + foreach($dirstrs as $dstr) { + $d = new PhingFile($dir, $dstr); + $result[] = $d->getAbsolutePath(); + } + + } elseif ($o instanceof FileList) { + $fl = $o; + $dirstrs = $fl->getFiles($this->project); + $dir = $fl->getDir($this->project); + foreach($dirstrs as $dstr) { + $d = new PhingFile($dir, $dstr); + $result[] = $d->getAbsolutePath(); + } + } + } + + return array_unique($result); + } + + + /** + * Returns a textual representation of the path, which can be used as + * CLASSPATH or PATH environment variable definition. + * @return string A textual representation of the path. + */ + public function __toString() { + + $list = $this->listPaths(); + + // empty path return empty string + if (empty($list)) { + return ""; + } + + return implode(PATH_SEPARATOR, $list); + } + + /** + * Splits a PATH (with : or ; as separators) into its parts. + * @param Project $project + * @param string $source + */ + public static function translatePath(Project $project, $source) { + $result = array(); + if ($source == null) { + return ""; + } + + $tok = new PathTokenizer($source); + $element = ""; + while ($tok->hasMoreTokens()) { + $pathElement = $tok->nextToken(); + try { + $element .= self::resolveFile($project, $pathElement); + } catch (BuildException $e) { + $this->project->log("Dropping path element " . $pathElement + . " as it is not valid relative to the project", + PROJECT_MSG_VERBOSE); + } + + for ($i = 0, $_i=strlen($element); $i < $_i; $i++) { + self::translateFileSep($element, $i); + } + $result[] = $element; + } + + return $result; + } + + /** + * Returns its argument with all file separator characters + * replaced so that they match the local OS conventions. + */ + public static function translateFile($source) { + if ($source == null) { + return ""; + } + + $result = $source; + for ($i = 0, $_i=strlen($source); $i < $_i; $i++) { + self::translateFileSep($result, $i); + } + + return $result; + } + + /** + * Translates all occurrences of / or \ to correct separator of the + * current platform and returns whether it had to do any + * replacements. + */ + protected static function translateFileSep(&$buffer, $pos) { + if ($buffer{$pos} == '/' || $buffer{$pos} == '\\') { + $buffer{$pos} = DIRECTORY_SEPARATOR; + return true; + } + return false; + } + + /** + * How many parts does this Path instance consist of. + * DEV NOTE: expensive call! list is generated, counted, and then + * discareded. + * @return int + */ + public function size() { + return count($this->listPaths()); + } + + /** + * Return a Path that holds the same elements as this instance. + */ + public function __clone() { + $p = new Path($this->project); + $p->append($this); + return $p; + } + + /** + * Overrides the version of DataType to recurse on all DataType + * child elements that may have been added. + * @throws BuildException + */ + public function dieOnCircularReference(&$stk, Project $p) { + + if ($this->checked) { + return; + } + + // elements can contain strings, FileSets, Reference, etc. + foreach($this->elements as $o) { + + if ($o instanceof Reference) { + $o = $o->getReferencedObject($p); + } + + if ($o instanceof DataType) { + if (in_array($o, $stk, true)) { + throw $this->circularReference(); + } else { + array_push($stk, $o); + $o->dieOnCircularReference($stk, $p); + array_pop($stk); + } + } + } + + $this->checked = true; + } + + /** + * Resolve a filename with Project's help - if we know one that is. + * + *

        Assume the filename is absolute if project is null.

        + */ + private static function resolveFile(Project $project, $relativeName) { + if ($project !== null) { + $f = $project->resolveFile($relativeName); + return $f->getAbsolutePath(); + } + return $relativeName; + } + +} + + +/** + * Helper class, holds the nested <pathelement> values. + */ +class PathElement { + + private $parts = array(); + private $outer; + + public function __construct(Path $outer) { + $this->outer = $outer; + } + + public function setDir(PhingFile $loc) { + $this->parts = array(Path::translateFile($loc->getAbsolutePath())); + } + + public function setPath($path) { + $this->parts = Path::translatePath($this->outer->getProject(), $path); + } + + public function getParts() { + return $this->parts; + } +} +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/types/PatternSet.php b/buildscripts/phing/classes/phing/types/PatternSet.php new file mode 100644 index 00000000..2963ab9e --- /dev/null +++ b/buildscripts/phing/classes/phing/types/PatternSet.php @@ -0,0 +1,449 @@ +. + */ + +include_once 'phing/system/io/FileReader.php'; +include_once 'phing/types/DataType.php'; + +/** + * The patternset storage component. Carries all necessary data and methods + * for the patternset stuff. + * + * @author Andreas Aderhold, andi@binarycloud.com + * @version $Revision: 1.8 $ + * @package phing.types + */ +class PatternSet extends DataType { + + private $includeList = array(); + private $excludeList = array(); + private $includesFileList = array(); + private $excludesFileList = array(); + + /** + * Makes this instance in effect a reference to another PatternSet + * instance. + * You must not set another attribute or nest elements inside + * this element if you make it a reference. + */ + function setRefid(Reference $r) { + if (!empty($this->includeList) || !empty($this->excludeList)) { + throw $this->tooManyAttributes(); + } + parent::setRefid($r); + } + + + /** + * Add a name entry on the include list + * + * @returns PatternSetNameEntry Reference to object + * @throws BuildException + */ + function createInclude() { + if ($this->isReference()) { + throw $this->noChildrenAllowed(); + } + return $this->addPatternToList($this->includeList); + } + + + /** + * Add a name entry on the include files list + * + * @returns PatternSetNameEntry Reference to object + * @throws BuildException + */ + function createIncludesFile() { + if ($this->isReference()) { + throw $this->noChildrenAllowed(); + } + return $this->addPatternToList($this->includesFileList); + } + + /** + * Add a name entry on the exclude list + * + * @returns PatternSetNameEntry Reference to object + * @throws BuildException + */ + function createExclude() { + if ($this->isReference()) { + throw $this->noChildrenAllowed(); + } + return $this->addPatternToList($this->excludeList); + } + + /** + * add a name entry on the exclude files list + * + * @returns PatternSetNameEntry Reference to object + * @throws BuildException + */ + + function createExcludesFile() { + if ($this->isReference()) { + throw $this->noChildrenAllowed(); + return; + } + return $this->addPatternToList($this->excludesFileList); + } + + + /** + * Sets the set of include patterns. Patterns may be separated by a comma + * or a space. + * + * @param string the string containing the include patterns + * @returns void + * @throws BuildException + */ + function setIncludes($includes) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + if ($includes !== null && strlen($includes) > 0) { + $tok = strtok($includes, ", "); + while ($tok !== false) { + $o = $this->createInclude(); + $o->setName($tok); + $tok = strtok(", "); + } + } + } + + + /** + * Sets the set of exclude patterns. Patterns may be separated by a comma + * or a space. + * + * @param string the string containing the exclude patterns + * @returns void + * @throws BuildException + */ + + function setExcludes($excludes) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + if ($excludes !== null && strlen($excludes) > 0) { + $tok = strtok($excludes, ", "); + while ($tok !== false) { + $o = $this->createExclude(); + $o->setName($tok); + $tok = strtok(", "); + } + } + } + + /** + * add a name entry to the given list + * + * @param array List onto which the nameentry should be added + * @returns PatternSetNameEntry Reference to the created PsetNameEntry instance + */ + private function addPatternToList(&$list) { + $num = array_push($list, new PatternSetNameEntry()); + return $list[$num-1]; + } + + /** + * Sets the name of the file containing the includes patterns. + * + * @param includesFile The file to fetch the include patterns from. + */ + function setIncludesFile($includesFile) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + if ($includesFile instanceof File) { + $includesFile = $includesFile->getPath(); + } + $o = $this->createIncludesFile(); + $o->setName($includesFile); + } + + /** + * Sets the name of the file containing the excludes patterns. + * + * @param excludesFile The file to fetch the exclude patterns from. + */ + function setExcludesFile($excludesFile) { + if ($this->isReference()) { + throw $this->tooManyAttributes(); + } + if ($excludesFile instanceof File) { + $excludesFile = $excludesFile->getPath(); + } + $o = $this->createExcludesFile(); + $o->setName($excludesFile); + } + + + /** + * Reads path matching patterns from a file and adds them to the + * includes or excludes list + */ + private function readPatterns(PhingFile $patternfile, &$patternlist, Project $p) { + $patternReader = null; + try { + // Get a FileReader + $patternReader = new BufferedReader(new FileReader($patternfile)); + + // Create one NameEntry in the appropriate pattern list for each + // line in the file. + $line = $patternReader->readLine(); + while ($line !== null) { + if (!empty($line)) { + $line = $p->replaceProperties($line); + $this->addPatternToList($patternlist)->setName($line); + } + $line = $patternReader->readLine(); + } + + } catch (IOException $ioe) { + $msg = "An error occured while reading from pattern file: " . $patternfile->__toString(); + if($patternReader) $patternReader->close(); + throw new BuildException($msg, $ioe); + } + + $patternReader->close(); + } + + + /** Adds the patterns of the other instance to this set. */ + function append($other, $p) { + if ($this->isReference()) { + throw new BuildException("Cannot append to a reference"); + } + + $incl = $other->getIncludePatterns($p); + if ($incl !== null) { + foreach($incl as $incl_name) { + $o = $this->createInclude(); + $o->setName($incl_name); + } + } + + $excl = $other->getExcludePatterns($p); + if ($excl !== null) { + foreach($excl as $excl_name) { + $o = $this->createExclude(); + $o->setName($excl_name); + } + } + } + + /** Returns the filtered include patterns. */ + function getIncludePatterns(Project $p) { + if ($this->isReference()) { + $o = $this->getRef($p); + return $o->getIncludePatterns($p); + } else { + $this->readFiles($p); + return $this->makeArray($this->includeList, $p); + } + } + + /** Returns the filtered exclude patterns. */ + function getExcludePatterns(Project $p) { + if ($this->isReference()) { + $o = $this->getRef($p); + return $o->getExcludePatterns($p); + } else { + $this->readFiles($p); + return $this->makeArray($this->excludeList, $p); + } + } + + /** helper for FileSet. */ + function hasPatterns() { + return (boolean) count($this->includesFileList) > 0 || count($this->excludesFileList) > 0 + || count($this->includeList) > 0 || count($this->excludeList) > 0; + } + + /** + * Performs the check for circular references and returns the + * referenced PatternSet. + */ + function getRef(Project $p) { + if (!$this->checked) { + $stk = array(); + array_push($stk, $this); + $this->dieOnCircularReference($stk, $p); + } + $o = $this->ref->getReferencedObject($p); + if (!($o instanceof PatternSet)) { + $msg = $this->ref->getRefId()." doesn't denote a patternset"; + throw new BuildException($msg); + } else { + return $o; + } + } + + /** Convert a array of PatternSetNameEntry elements into an array of Strings. */ + private function makeArray(&$list, Project $p) { + + if (count($list) === 0) { + return null; + } + + $tmpNames = array(); + foreach($list as $ne) { + $pattern = (string) $ne->evalName($p); + if ($pattern !== null && strlen($pattern) > 0) { + array_push($tmpNames, $pattern); + } + } + return $tmpNames; + } + + /** Read includesfile or excludesfile if not already done so. */ + private function readFiles(Project $p) { + if (!empty($this->includesFileList)) { + foreach($this->includesFileList as $ne) { + $fileName = (string) $ne->evalName($p); + if ($fileName !== null) { + $inclFile = $p->resolveFile($fileName); + if (!$inclFile->exists()) { + throw new BuildException("Includesfile ".$inclFile->getAbsolutePath()." not found."); + } + $this->readPatterns($inclFile, $this->includeList, $p); + } + } + $this->includesFileList = array(); + } + + if (!empty($this->excludesFileList)) { + foreach($this->excludesFileList as $ne) { + $fileName = (string) $ne->evalName($p); + if ($fileName !== null) { + $exclFile = $p->resolveFile($fileName); + if (!$exclFile->exists()) { + throw new BuildException("Excludesfile ".$exclFile->getAbsolutePath()." not found."); + return; + } + $this->readPatterns($exclFile, $this->excludeList, $p); + } + } + $this->excludesFileList = array(); + } + } + + + function toString() { + + // We can't compile includeList into array because, toString() does + // not know about project: + // + // $includes = $this->makeArray($this->includeList, $this->project); + // $excludes = $this->makeArray($this->excludeList, $this->project); + + if (empty($this->includeList)) { + $includes = "empty"; + } else { + $includes = ""; + foreach($this->includeList as $ne) { + $includes .= $ne->toString() . ","; + } + $includes = rtrim($includes, ","); + } + + if (empty($this->excludeList)) { + $excludes = "empty"; + } else { + $excludes = ""; + foreach($this->excludeList as $ne) { + $excludes .= $ne->toString() . ","; + } + $excludes = rtrim($excludes, ","); + } + + return "patternSet{ includes: $includes excludes: $excludes }"; + } +} + + +/* + * Note, this class here should become a nested class to + * PatternSet (PatternSet:NameEntry) as it is only needed + * internally. + * This is not possible with php 4.x right now so we place + * this class (against good style) in this file. + */ + +class PatternSetNameEntry { + + private $name = null; + private $ifCond = null; + private $unlessCond = null; + + function setName($name) { + $this->name = (string) $name; + } + + + function setIf($cond) { + $this->ifCond = (string) $cond; + } + + + function setUnless($cond) { + $this->unlessCond = (string) $cond; + } + + + function getName() { + return $this->name; + } + + + function evalName($project) { + return $this->valid($project) ? $this->name : null; + } + + + function valid($project) { + if ($this->ifCond !== null && $project->getProperty($this->ifCond) === null) { + return false; + } else if ($this->unlessCond !== null && $project->getProperty($this->unlessCond) !== null) { + return false; + } + return true; + } + + + function toString() { + $buf = $this->name; + if (($this->ifCond !== null) || ($this->unlessCond !== null)) { + $buf .= ":"; + $connector = ""; + + if ($this->ifCond !== null) { + $buf .= "if->{$this->ifCond}"; + $connector = ";"; + } + if ($this->unlessCond !== null) { + $buf .= "$connector unless->{$this->unlessCond}"; + } + } + return $buf; + } +} diff --git a/buildscripts/phing/classes/phing/types/PhingFilterReader.php b/buildscripts/phing/classes/phing/types/PhingFilterReader.php new file mode 100644 index 00000000..eb45f894 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/PhingFilterReader.php @@ -0,0 +1,136 @@ +. +*/ + +include_once 'phing/types/DataType.php'; +include_once 'phing/types/Parameter.php'; + +/* + * A PhingFilterReader is a wrapper class that encloses the className + * and configuration of a Configurable FilterReader. + * + * @author Yannick Lecaillez + * @version $Revision: 1.9 $ + * @see FilterReader + * @package phing.types +*/ +class PhingFilterReader extends DataType { + + private $className; + private $parameters = array(); + private $classPath; + + function setClassName($className) { + $this->className = $className; + } + + function getClassName() { + return $this->className; + } + + /** + * Set the classpath to load the FilterReader through (attribute). + * @param Path $classpath + */ + function setClasspath(Path $classpath) { + if ( $this->isReference() ) { + throw $this->tooManyAttributes(); + } + if ( $this->classPath === null ) { + $this->classPath = $classpath; + } else { + $this->classPath->append($classpath); + } + } + + /* + * Set the classpath to load the FilterReader through (nested element). + */ + function createClasspath() { + if ( $this->isReference() ) { + throw $this->noChildrenAllowed(); + } + if ( $this->classPath === null ) { + $this->classPath = new Path($this->project); + } + return $this->classPath->createPath(); + } + + function getClasspath() { + return $this->classPath; + } + + function setClasspathRef(Reference $r) { + if ( $this->isReference() ) { + throw $this->tooManyAttributes(); + } + $o = $this->createClasspath(); + $o->setRefid($r); + } + + function addParam(Parameter $param) { + $this->parameters[] = $param; + } + + function createParam() { + $num = array_push($this->parameters, new Parameter()); + return $this->parameters[$num-1]; + } + + function getParams() { + // We return a COPY + $ret = array(); + for($i=0,$size=count($this->parameters); $i < $size; $i++) { + $ret[] = clone $this->parameters[$i]; + } + return $ret; + } + + /* + * Makes this instance in effect a reference to another PhingFilterReader + * instance. + * + *

        You must not set another attribute or nest elements inside + * this element if you make it a reference.

        + * + * @param Reference $r the reference to which this instance is associated + * @exception BuildException if this instance already has been configured. + */ + function setRefid(Reference $r) { + if ( (count($this->parameters) !== 0) || ($this->className !== null) ) { + throw $this->tooManyAttributes(); + } + $o = $r->getReferencedObject($this->getProject()); + if ( $o instanceof PhingFilterReader ) { + $this->setClassName($o->getClassName()); + $this->setClasspath($o->getClassPath()); + foreach($o->getParams() as $p) { + $this->addParam($p); + } + } else { + $msg = $r->getRefId()." doesn\'t refer to a PhingFilterReader"; + throw new BuildException($msg); + } + + parent::setRefid($r); + } +} + +?> diff --git a/buildscripts/phing/classes/phing/types/Reference.php b/buildscripts/phing/classes/phing/types/Reference.php new file mode 100644 index 00000000..c226917d --- /dev/null +++ b/buildscripts/phing/classes/phing/types/Reference.php @@ -0,0 +1,56 @@ +. + */ + +/** Class to hold a reference to another object in the project. + * @package phing.types + */ +class Reference { + + protected $refid; + + function __construct($id = null) { + if ($id !== null) { + $this->setRefId($id); + } + } + + function setRefId($id) { + $this->refid = (string) $id; + } + + function getRefId() { + return $this->refid; + } + + /** returns reference to object in references container of project */ + function getReferencedObject($project) { + if ($this->refid === null) { + throw new BuildException("No reference specified"); + } + $refs = $project->getReferences(); + $o = @$refs[$this->refid]; + if (!is_object($o)) { + throw new BuildException("Reference {$this->refid} not found."); + } + return $o; + } +} +?> diff --git a/buildscripts/phing/classes/phing/types/RegularExpression.php b/buildscripts/phing/classes/phing/types/RegularExpression.php new file mode 100644 index 00000000..67850c23 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/RegularExpression.php @@ -0,0 +1,105 @@ +. +*/ + +include_once 'phing/types/DataType.php'; +include_once 'phing/Project.php'; +include_once 'phing/util/regexp/Regexp.php'; + +/* + * A regular expression datatype. Keeps an instance of the + * compiled expression for speed purposes. This compiled + * expression is lazily evaluated (it is compiled the first + * time it is needed). The syntax is the dependent on which + * regular expression type you are using. + * + * @author Yannick Lecaillez + * @version $Revision: 1.6 $ $Date: 2003/12/24 12:38:42 $ + * @access public + * @see phing.util.regex.RegexMatcher + * @package phing.types +*/ +class RegularExpression extends DataType { + + private $regexp = null; + private $ignoreCase = false; + + function __construct() { + $this->regexp = new Regexp(); + } + + function setPattern($pattern) { + $this->regexp->setPattern($pattern); + } + + function setReplace($replace) { + $this->regexp->setReplace($replace); + } + + function getPattern($p) { + if ( $this->isReference() ) { + $ref = $this->getRef($p); + return $ref->getPattern($p); + } + return $this->regexp->getPattern(); + } + + function getReplace($p) { + if ( $this->isReference() ) { + $ref = $this->getRef($p); + return $ref->getReplace($p); + } + + return $this->regexp->getReplace(); + } + + function setIgnoreCase($bit) { + $this->regexp->setIgnoreCase($bit); + } + + function getIgnoreCase() { + return $this->regexp->getIgnoreCase(); + } + + function getRegexp(Project $p) { + if ( $this->isReference() ) { + $ref = $this->getRef($p); + return $ref->getRegexp($p); + } + return $this->regexp; + } + + function getRef(Project $p) { + if ( !$this->checked ) { + $stk = array(); + array_push($stk, $this); + $this->dieOnCircularReference($stk, $p); + } + + $o = $this->ref->getReferencedObject($p); + if ( !($o instanceof RegularExpression) ) { + throw new BuildException($this->ref->getRefId()." doesn't denote a RegularExpression"); + } else { + return $o; + } + } +} + +?> diff --git a/buildscripts/phing/classes/phing/types/TokenReader.php b/buildscripts/phing/classes/phing/types/TokenReader.php new file mode 100644 index 00000000..acd7d616 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/TokenReader.php @@ -0,0 +1,66 @@ +. +*/ + +// include_once 'phing/system/io/Reader.php'; // really this is unrelated to Reader +include_once 'phing/system/io/IOException.php'; +include_once 'phing/filters/ReplaceTokens.php'; // For class Token + +/** + * Abstract class for TokenReaders. + * + * @author Manuel Holtgewe + * @version $Revision: 1.5 $ + * @package phing.filters.util + */ +abstract class TokenReader { + + /** + * Reference to the Project the TokenReader is used in. + * @var Project + */ + protected $project; + + /** + * Constructor + * @param object Reference to the project the TokenReader is used in. + */ + function __construct(Project $project) { + $this->project = $project; + } + + /** + * Utility function for logging + */ + function log($level, $msg) { + $this->project->log($level, $msg); + } + + /** + * Reads the next token from the Reader + * + * @throws IOException - On error + * @return string + */ + abstract public function readToken(); + +} + +?> diff --git a/buildscripts/phing/classes/phing/types/TokenSource.php b/buildscripts/phing/classes/phing/types/TokenSource.php new file mode 100644 index 00000000..c073ece0 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/TokenSource.php @@ -0,0 +1,157 @@ +. +*/ + +require_once 'phing/types/DataType.php'; +include_once 'phing/util/StringHelper.php'; + +/** + * A parameter is composed of a name, type and value. + * + * Example of usage: + * + * + * + * + * + * + * + * + * or: + * + * + * + * + * + * + * + * @author Yannick Lecaillez + * @package phing.types + */ +class TokenSource extends DataType { + + /** + * String to hold the path to the TokenReader + * @var string + */ + protected $classname = null; + + /** + * Array holding parameters for the wrapped TokenReader. + * @var array + */ + protected $parameters = array(); + + /** + * Reference to the TokenReader used by this TokenSource + * @var TokenReader + */ + protected $reader; + + /** + * Array with key/value pairs of tokens + */ + protected $tokens = array(); + + /** + * This method is called to load the sources from the reader + * into the buffer of the source. + */ + function load() { + // Create new Reader + if ($this->classname === null) { + throw new BuildException("No Classname given to TokenSource."); + } + + $classname = Phing::import($this->classname); + $this->reader = new $classname($this->project); + + // Configure Reader + $this->configureTokenReader($this->reader); + + // Load Tokens + try { + while ($token = $this->reader->readToken()) { + $this->tokens[] = $token; + } + } catch (BuildException $e) { + $this->log("Error reading TokenSource: " . $e->getMessage(), PROJECT_MSG_WARN); + } catch (IOException $e) { + $this->log("Error reading TokenSource: " . $e->getMessage(), PROJECT_MSG_WARN); + } + } + + /** + * This function uses the wrapper to read the tokens and then + * returns them. + * + * @access public + */ + function getTokens() { + if ($this->tokens === null) + $this->Load(); + + return $this->tokens; + } + + /** + * Configures a TokenReader with the parameters passed to the + * TokenSource. + * @param TokenReader $reader + */ + private function configureTokenReader(TokenReader $reader) { + $count = count($this->parameters); + for ($i = 0; $i < $count; $i++) { + $method_name = "Set" . $this->parameters[$i]->getName(); + $value = $this->parameters[$i]->getValue(); + $reader->$method_name($value); + } + } + + /** + * Set the classname (dot-path) to use for handling token replacement. + * @param string $c + */ + function setClassname($c) { + $this->classname = $c; + } + + /** + * Returns the qualified classname (dot-path) to use for handling token replacement. + * @return string + */ + function getClassname() { + return $this->classname; + } + + /** + * Create nested tag. + * Uses standard name/value Parameter class. + * @return Parameter + */ + function createParam() { + $num = array_push($this->parameters, new Parameter()); + return $this->parameters[$num-1]; + } +} + + +?> diff --git a/buildscripts/phing/classes/phing/types/defaults.properties b/buildscripts/phing/classes/phing/types/defaults.properties new file mode 100644 index 00000000..a2d86350 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/defaults.properties @@ -0,0 +1,13 @@ +# phing default types +commandline=phing.types.Commandline +fileset=phing.types.FileSet +dirset=phing.types.DirSet +filelist=phing.types.FileList +patternset=phing.types.PatternSet +mapper=phing.types.Mapper +filterchain=phing.types.FilterChain +filterreader=phing.types.PhingFilterReader +regexp=phing.types.RegularExpression +param=phing.types.Parameter +path=phing.types.Path +selector=phing.types.selectors.SelectSelector \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/types/selectors/AndSelector.php b/buildscripts/phing/classes/phing/types/selectors/AndSelector.php new file mode 100644 index 00000000..3801091f --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/AndSelector.php @@ -0,0 +1,67 @@ +. + */ + +require_once 'phing/types/selectors/BaseSelectorContainer.php'; + +/** + * This selector has a collection of other selectors, all of which have to + * select a file in order for this selector to select it. + * + * @author Hans Lellelid, hans@xmpl.org (Phing) + * @author Bruce Atherton (Ant) + * @package phing.types.selectors + */ +class AndSelector extends BaseSelectorContainer { + + public function toString() { + $buf = ""; + if ($this->hasSelectors()) { + $buf .= "{andselect: "; + $buf .= parent::toString(); + $buf .= "}"; + } + return $buf; + } + + /** + * Returns true (the file is selected) only if all other selectors + * agree that the file should be selected. + * + * @param basedir the base directory the scan is being done from + * @param filename the name of the file to check + * @param file a PhingFile object for the filename that the selector + * can use + * @return whether the file should be selected or not + */ + public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + $this->validate(); + $selectors = $this->selectorElements(); + for($i=0,$size=count($selectors); $i < $size; $i++) { + $result = $selectors[$i]->isSelected($basedir, $filename, $file); + if (!$result) { + return false; + } + } + return true; + } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/BaseExtendSelector.php b/buildscripts/phing/classes/phing/types/selectors/BaseExtendSelector.php new file mode 100644 index 00000000..5acc54dd --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/BaseExtendSelector.php @@ -0,0 +1,62 @@ +. + */ + +require_once 'phing/types/selectors/ExtendFileSelector.php'; +require_once 'phing/types/selectors/BaseSelector.php'; +include_once 'phing/types/Parameter.php'; + +/** + * Convenience base class for all selectors accessed through ExtendSelector. + * It provides support for gathering the parameters together as well as for + * assigning an error message and throwing a build exception if an error is + * detected. + * + * @author Hans Lellelid, hans@xmpl.org (Phing) + * @author Bruce Atherton, bruce@callenish.com (Ant) + * @package phing.types.selectors + */ +abstract class BaseExtendSelector extends BaseSelector implements ExtendFileSelector { + + /** The passed in parameter array. */ + protected $parameters = null; + + /** + * Set all the Parameters for this custom selector, collected by + * the ExtendSelector class. + * + * @param parameters the complete set of parameters for this selector + */ + public function setParameters($parameters) { + $this->parameters = $parameters; + } + + /** + * Allows access to the parameters gathered and set within the + * <custom> tag. + * + * @return the set of parameters defined for this selector + */ + protected function getParameters() { + return $this->parameters; + } +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/BaseSelector.php b/buildscripts/phing/classes/phing/types/selectors/BaseSelector.php new file mode 100644 index 00000000..e229fc24 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/BaseSelector.php @@ -0,0 +1,84 @@ +. + */ + +require_once 'phing/types/selectors/FileSelector.php'; + +/** + * A convenience base class that you can subclass Selectors from. It + * provides some helpful common behaviour. Note that there is no need + * for Selectors to inherit from this class, it is only necessary that + * they implement FileSelector. + * + * @author Bruce Atherton + * @package phing.types.selectors + */ +abstract class BaseSelector extends DataType implements FileSelector { + + private $errmsg = null; + + /** + * Allows all selectors to indicate a setup error. Note that only + * the first error message is recorded. + * + * @param msg The error message any BuildException should throw. + */ + public function setError($msg) { + if ($this->errmsg === null) { + $this->errmsg = $msg; + } + } + + /** + * Returns any error messages that have been set. + * + * @return the error condition + */ + public function getError() { + return $this->errmsg; + } + + + /** + *

        Subclasses can override this method to provide checking of their + * state. So long as they call validate() from isSelected(), this will + * be called automatically (unless they override validate()).

        + *

        Implementations should check for incorrect settings and call + * setError() as necessary.

        + */ + public function verifySettings() { + } + + /** + * Subclasses can use this to throw the requisite exception + * in isSelected() in the case of an error condition. + */ + public function validate() { + if ($this->getError() === null) { + $this->verifySettings(); + } + if ($this->getError() !== null) { + throw new BuildException($this->errmsg); + } + } + +} + + diff --git a/buildscripts/phing/classes/phing/types/selectors/BaseSelectorContainer.php b/buildscripts/phing/classes/phing/types/selectors/BaseSelectorContainer.php new file mode 100644 index 00000000..19b84b00 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/BaseSelectorContainer.php @@ -0,0 +1,270 @@ +. + */ + +require_once 'phing/types/selectors/SelectorContainer.php'; +require_once 'phing/types/selectors/BaseSelector.php'; + +/** + * This is the base class for selectors that can contain other selectors. + * + * @author Bruce Atherton (Ant) + * @package phing.types.selectors + */ +abstract class BaseSelectorContainer extends BaseSelector implements SelectorContainer { + + private $selectorsList = array(); + + /** + * Indicates whether there are any selectors here. + */ + public function hasSelectors() { + return !(empty($this->selectorsList)); + } + + /** + * Gives the count of the number of selectors in this container + */ + public function selectorCount() { + return count($this->selectorsList); + } + + /** + * Returns a copy of the selectors as an array. + */ + public function getSelectors(Project $p) { + $result = array(); + for($i=0,$size=count($this->selectorsList); $i < $size; $i++) { + $result[] = clone $this->selectorsList[$i]; + } + return $result; + } + + /** + * Returns an array for accessing the set of selectors (not a copy). + */ + public function selectorElements() { + return $this->selectorsList; + } + + /** + * Convert the Selectors within this container to a string. This will + * just be a helper class for the subclasses that put their own name + * around the contents listed here. + * + * @return comma separated list of Selectors contained in this one + */ + public function toString() { + $buf = ""; + $arr = $this->selectorElements(); + for($i=0,$size=count($arr); $i < $size; $i++) { + $buf .= $arr[$i]->toString() . (isset($arr[$i+1]) ? ', ' : ''); + } + return $buf; + } + + /** + * Add a new selector into this container. + * + * @param selector the new selector to add + * @return the selector that was added + */ + public function appendSelector(FileSelector $selector) { + $this->selectorsList[] = $selector; + } + + /** + *

        This implementation validates the container by calling + * verifySettings() and then validates each contained selector + * provided that the selector implements the validate interface. + *

        + *

        Ordinarily, this will validate all the elements of a selector + * container even if the isSelected() method of some elements is + * never called. This has two effects:

        + *
          + *
        • Validation will often occur twice. + *
        • Since it is not required that selectors derive from + * BaseSelector, there could be selectors in the container whose + * error conditions are not detected if their isSelected() call + * is never made. + *
        + */ + public function validate() { + $this->verifySettings(); + $errmsg = $this->getError(); + if ($errmsg !== null) { + throw new BuildException($errmsg); + } + foreach($this->selectorsList as $o) { + if ($o instanceof BaseSelector) { + $o->validate(); + } + } + } + + /* Methods below all add specific selectors */ + + /** + * add a "Select" selector entry on the selector list + */ + public function createSelector() { + $o = new SelectSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add an "And" selector entry on the selector list + */ + public function createAnd() { + $o = new AndSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add an "Or" selector entry on the selector list + */ + public function createOr() { + $o = new OrSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a "Not" selector entry on the selector list + */ + public function createNot() { + $o = new NotSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a "None" selector entry on the selector list + */ + public function createNone() { + $o = new NoneSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a majority selector entry on the selector list + */ + public function createMajority() { + $o = new MajoritySelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a selector date entry on the selector list + */ + public function createDate() { + $o = new DateSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a selector size entry on the selector list + */ + public function createSize() { + $o = new SizeSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a selector filename entry on the selector list + */ + public function createFilename() { + $o = new FilenameSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add an extended selector entry on the selector list + */ + public function createCustom() { + $o = new ExtendSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a contains selector entry on the selector list + */ + public function createContains() { + $o = new ContainsSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a contains selector entry on the selector list + */ + public function createContainsRegexp() { + $o = new ContainsRegexpSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a present selector entry on the selector list + */ + public function createPresent() { + $o = new PresentSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a depth selector entry on the selector list + */ + public function createDepth() { + $o = new DepthSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a depends selector entry on the selector list + */ + public function createDepend() { + $o = new DependSelector(); + $this->appendSelector($o); + return $o; + } + + /** + * add a type selector entry on the selector list + */ + public function createType() { + $o = new TypeSelector(); + $this->appendSelector($o); + return $o; + } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/ContainsRegexpSelector.php b/buildscripts/phing/classes/phing/types/selectors/ContainsRegexpSelector.php new file mode 100644 index 00000000..39afd2fa --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/ContainsRegexpSelector.php @@ -0,0 +1,164 @@ +. + */ + +require_once 'phing/types/selectors/BaseExtendSelector.php'; +include_once 'phing/types/RegularExpression.php'; + +/** + * Selector that filters files based on whether they contain a + * particular string using regexp. + * + * @author Hans Lellelid (Phing) + * @author Bruce Atherton (Ant) + * @version $Revision: 1.3 $ + * @package phing.types.selectors + */ +class ContainsRegexpSelector extends BaseExtendSelector { + + /** @var string The expression set from XML. */ + private $userProvidedExpression; + + /** @var Regexp */ + private $myExpression; + + private $casesensitive = true; + + /** @var RegularExpression */ + private $myRegExp; + + const EXPRESSION_KEY = "expression"; + + const CASE_KEY = "casesensitive"; + + public function toString() { + $buf = "{containsregexpselector expression: "; + $buf .= $this->userProvidedExpression; + $buf .= " casesensitive: "; + if ($this->casesensitive) { + $buf .= "true"; + } else { + $buf .= "false"; + } + $buf .= "}"; + return $buf; + } + + /** + * The expression to match on within a file. + * + * @param string $exp the string that a file must contain to be selected. + */ + public function setExpression($exp) { + $this->userProvidedExpression = $exp; + } + + /** + * Whether to ignore case in the regex match. + * + * @param boolean $casesensitive whether to pay attention to case sensitivity + */ + public function setCasesensitive($casesensitive) { + $this->casesensitive = $casesensitive; + } + + /** + * When using this as a custom selector, this method will be called. + * It translates each parameter into the appropriate setXXX() call. + * + * @param array $parameters the complete set of parameters for this selector + */ + public function setParameters($parameters) { + parent::setParameters($parameters); + if ($parameters !== null) { + for ($i=0,$size=count($parameters); $i < $size; $i++) { + $paramname = $parameters[$i]->getName(); + switch(strtolower($paramname)) { + case self::EXPRESSION_KEY: + $this->setExpression($parameters[$i]->getValue()); + break; + case self::CASE_KEY: + $this->setCasesensitive($parameters[$i]->getValue()); + break; + default: + $this->setError("Invalid parameter " . $paramname); + } + } // for each param + } // if params + } + + /** + * Checks to make sure all settings are kosher. In this case, it + * means that the pattern attribute has been set. + * + */ + public function verifySettings() { + if ($this->userProvidedExpression === null) { + $this->setError("The expression attribute is required"); + } + } + + /** + * The heart of the matter. This is where the selector gets to decide + * on the inclusion of a file in a particular fileset. + * + * @param basedir the base directory the scan is being done from + * @param filename is the name of the file to check + * @param file a PhingFile object the selector can use + * @return whether the file should be selected or not + */ + public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + + $this->validate(); + + if ($file->isDirectory()) { + return true; + } + + if ($this->myRegExp === null) { + $this->myRegExp = new RegularExpression(); + $this->myRegExp->setPattern($this->userProvidedExpression); + if (!$this->casesensitive) { + $this->myRegExp->setIgnoreCase(true); + } + $this->myExpression = $this->myRegExp->getRegexp($this->getProject()); + } + + $in = null; + try { + $in = new BufferedReader(new FileReader($file)); + $teststr = $in->readLine(); + while ($teststr !== null) { + if ($this->myExpression->matches($teststr)) { + return true; + } + $teststr = $in->readLine(); + } + return false; + } catch (IOException $ioe) { + if ($in) $in->close(); + throw new BuildException("Could not read file " . $filename); + } + $in->close(); + } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/ContainsSelector.php b/buildscripts/phing/classes/phing/types/selectors/ContainsSelector.php new file mode 100644 index 00000000..d00ce995 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/ContainsSelector.php @@ -0,0 +1,151 @@ +. + */ + +include_once 'phing/types/selectors/BaseExtendSelector.php'; + +/** + * Selector that filters files based on whether they contain a + * particular string. + * + * @author Hans Lellelid (Phing) + * @author Bruce Atherton (Ant) + * @package phing.types.selectors + */ +class ContainsSelector extends BaseExtendSelector { + + private $contains = null; + private $casesensitive = true; + const CONTAINS_KEY = "text"; + const CASE_KEY = "casesensitive"; + + public function toString() { + $buf = "{containsselector text: "; + $buf .= $this->contains; + $buf .= " casesensitive: "; + if ($this->casesensitive) { + $buf .= "true"; + } else { + $buf .= "false"; + } + $buf .= "}"; + return $buf; + } + + /** + * The string to search for within a file. + * + * @param string $contains the string that a file must contain to be selected. + */ + public function setText($contains) { + $this->contains = $contains; + } + + /** + * Whether to ignore case in the string being searched. + * + * @param boolean $casesensitive whether to pay attention to case sensitivity + */ + public function setCasesensitive($casesensitive) { + $this->casesensitive = $casesensitive; + } + + /** + * When using this as a custom selector, this method will be called. + * It translates each parameter into the appropriate setXXX() call. + * + * @param array $parameters the complete set of parameters for this selector + */ + public function setParameters($parameters) { + parent::setParameters($parameters); + if ($parameters !== null) { + for ($i=0,$size=count($parameters); $i < $size; $i++) { + $paramname = $parameters[$i]->getName(); + switch(strtolower($paramname)) { + case self::CONTAINS_KEY: + $this->setText($parameters[$i]->getValue()); + break; + case self::CASE_KEY: + $this->setCasesensitive($parameters[$i]->getValue()); + break; + default: + $this->setError("Invalid parameter " . $paramname); + } + } // for each param + } // if params + } + + /** + * Checks to make sure all settings are kosher. In this case, it + * means that the pattern attribute has been set. + * + */ + public function verifySettings() { + if ($this->contains === null) { + $this->setError("The text attribute is required"); + } + } + + /** + * The heart of the matter. This is where the selector gets to decide + * on the inclusion of a file in a particular fileset. + * + * @param basedir the base directory the scan is being done from + * @param filename is the name of the file to check + * @param file a PhingFile object the selector can use + * @return whether the file should be selected or not + */ + public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + + $this->validate(); + + if ($file->isDirectory()) { + return true; + } + + $userstr = $this->contains; + if (!$this->casesensitive) { + $userstr = strtolower($this->contains); + } + + $in = null; + try { + $in = new BufferedReader(new FileReader($file)); + $teststr = $in->readLine(); + while ($teststr !== null) { + if (!$this->casesensitive) { + $teststr = strtolower($teststr); + } + if (strpos($teststr, $userstr) !== false) { + return true; + } + $teststr = $in->readLine(); + } + return false; + } catch (IOException $ioe) { + if ($in) $in->close(); + throw new BuildException("Could not read file " . $filename); + } + $in->close(); + } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/DateSelector.php b/buildscripts/phing/classes/phing/types/selectors/DateSelector.php new file mode 100644 index 00000000..96e5c3ba --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/DateSelector.php @@ -0,0 +1,214 @@ +. + */ + +require_once 'phing/types/selectors/BaseExtendSelector.php'; + +/** + * Selector that chooses files based on their last modified date. Ant uses + * millisecond precision (thanks to Java); PHP is forced to use only seconds + * precision. + * + * @author Hans Lellelid (Phing) + * @author Bruce Atherton (Ant) + * @version $Revision: 1.10 $ + * @package phing.types.selecctors + */ +class DateSelector extends BaseExtendSelector { + + private $seconds = -1; // millis in Ant, but PHP doesn't support that level of precision + private $dateTime = null; + private $includeDirs = false; + private $granularity = 0; + private $cmp = 2; + const MILLIS_KEY = "millis"; + const DATETIME_KEY = "datetime"; + const CHECKDIRS_KEY = "checkdirs"; + const GRANULARITY_KEY = "granularity"; + const WHEN_KEY = "when"; + private static $timeComparisons = array("before", "after", "equal"); + + public function __construct() { + //if (Os.isFamily("dos")) { + // granularity = 2000; + //} + } + + public function toString() { + $buf = "{dateselector date: "; + $buf .= $this->dateTime; + $buf .= " compare: "; + if ($this->cmp === 0) { + $buf .= "before"; + } elseif ($this->cmp === 1) { + $buf .= "after"; + } else { + $buf .= "equal"; + } + $buf .= " granularity: "; + $buf .= $this->granularity; + $buf .= "}"; + return $buf; + } + + /** + * For users that prefer to express time in seconds since 1970 + * + * @param int $seconds the time to compare file's last modified date to, + * expressed in milliseconds + */ + public function setSeconds($seconds) { + $this->seconds = (int) $seconds; + } + + /** + * Returns the seconds value the selector is set for. + */ + public function getSeconds() { + return $this->seconds; + } + + /** + * Sets the date. The user must supply it in MM/DD/YYYY HH:MM AM_PM + * format + * + * @param string $dateTime a string in MM/DD/YYYY HH:MM AM_PM format + */ + public function setDatetime($dateTime) { + $dt = strtotime($dateTime); + if ($dt == -1) { + $this->setError("Date of " . $dateTime + . " Cannot be parsed correctly. It should be in" + . " a format parsable by PHP's strtotime() function."); + } else { + $this->dateTime = $dateTime; + $this->setSeconds($dt); + } + } + + /** + * Should we be checking dates on directories? + * + * @param boolean $includeDirs whether to check the timestamp on directories + */ + public function setCheckdirs($includeDirs) { + $this->includeDirs = (boolean) $includeDirs; + } + + /** + * Sets the number of milliseconds leeway we will give before we consider + * a file not to have matched a date. + * @param int $granularity + */ + public function setGranularity($granularity) { + $this->granularity = (int) $granularity; + } + + /** + * Sets the type of comparison to be done on the file's last modified + * date. + * + * @param string $cmp The comparison to perform + */ + public function setWhen($cmp) { + $idx = array_search($cmp, self::$timeComparisons, true); + if ($idx === null) { + $this->setError("Invalid value for ".WHEN_KEY.": ".$cmp); + } else { + $this->cmp = $idx; + } + } + + /** + * When using this as a custom selector, this method will be called. + * It translates each parameter into the appropriate setXXX() call. + * + * @param array $parameters the complete set of parameters for this selector + */ + public function setParameters($parameters) { + parent::setParameters($parameters); + if ($parameters !== null) { + for ($i=0,$size=count($parameters); $i < $size; $i++) { + $paramname = $parameters[$i]->getName(); + switch(strtolower($paramname)) { + case self::MILLIS_KEY: + $this->setMillis($parameters[$i]->getValue()); + break; + case self::DATETIME_KEY: + $this->setDatetime($parameters[$i]->getValue()); + break; + case self::CHECKDIRS_KEY: + $this->setCheckdirs($parameters[$i]->getValue()); + break; + case self::GRANULARITY_KEY: + $this->setGranularity($parameters[$i]->getValue()); + break; + case self::WHEN_KEY: + $this->setWhen($parameters[$i]->getValue()); + break; + default: + $this->setError("Invalid parameter " . $paramname); + } // switch + } + } + } + + /** + * This is a consistency check to ensure the selector's required + * values have been set. + */ + public function verifySettings() { + if ($this->dateTime === null && $this->seconds < 0) { + $this->setError("You must provide a datetime or the number of " + . "seconds."); + } elseif ($this->seconds < 0) { + $this->setError("Date of " . $this->dateTime + . " results in negative seconds" + . " value relative to epoch (January 1, 1970, 00:00:00 GMT)."); + } + } + + /** + * The heart of the matter. This is where the selector gets to decide + * on the inclusion of a file in a particular fileset. + * + * @param PhingFile $basedir the base directory the scan is being done from + * @param string $filename is the name of the file to check + * @param PhingFile $file is a PhingFile object the selector can use + * @return boolean Whether the file should be selected or not + */ + public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + $this->validate(); + if ($file->isDirectory() && ($this->includeDirs === false)) { + return true; + } + if ($this->cmp === 0) { + return (($file->lastModified() - $this->granularity) < $this->seconds); + } elseif ($this->cmp === 1) { + return (($file->lastModified() . $this->granularity) > $this->seconds); + } else { + return (abs($file->lastModified() - $this->seconds) <= $this->granularity); + } + } + +} + + diff --git a/buildscripts/phing/classes/phing/types/selectors/DependSelector.php b/buildscripts/phing/classes/phing/types/selectors/DependSelector.php new file mode 100644 index 00000000..db73c512 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/DependSelector.php @@ -0,0 +1,151 @@ +. + */ + +require_once 'phing/types/selectors/BaseSelector.php'; + +/** + * Selector that filters files based on whether they are newer than + * a matching file in another directory tree. It can contain a mapper + * element, so isn't available as an ExtendSelector (since those + * parameters can't hold other elements). + * + * @author Hans Lellelid (Phing) + * @author Bruce Atherton (Ant) + * @version $Revision: 1.8 $ + * @package phing.types.selectors + */ +class DependSelector extends BaseSelector { + + private $targetdir = null; + private $mapperElement = null; + private $map = null; + private $granularity = 0; + + public function __construct() { + // not yet supported: + //if (Os.isFamily("dos")) { + // $this->granularity = 2000; + //} + } + + public function toString() { + $buf = "{dependselector targetdir: "; + if ($this->targetdir === null) { + $buf .= "NOT YET SET"; + } else { + $buf .= $this->targetdir->getName(); + } + $buf .= " granularity: "; + $buf .= $this->granularity; + if ($this->map !== null) { + $buf .= " mapper: "; + $buf .= $this->map->toString(); + } elseif ($this->mapperElement !== null) { + $buf .= " mapper: "; + $buf .= $this->mapperElement->toString(); + } + $buf .= "}"; + return $buf; + } + + /** + * The name of the file or directory which is checked for out-of-date + * files. + * + * @param targetdir the directory to scan looking for files. + */ + public function setTargetdir(PhingFile $targetdir) { + $this->targetdir = $targetdir; + } + + /** + * Sets the number of milliseconds leeway we will give before we consider + * a file out of date. + */ + public function setGranularity($granularity) { + $this->granularity = (int) granularity; + } + + /** + * Defines the FileNameMapper to use (nested mapper element). + * @throws BuildException + */ + public function createMapper() { + if ($this->mapperElement !== null) { + throw new BuildException("Cannot define more than one mapper"); + } + $this->mapperElement = new Mapper($this->project); + return $this->mapperElement; + } + + + /** + * Checks to make sure all settings are kosher. In this case, it + * means that the dest attribute has been set and we have a mapper. + */ + public function verifySettings() { + if ($this->targetdir === null) { + $this->setError("The targetdir attribute is required."); + } + if ($this->mapperElement === null) { + $this->map = new IdentityMapper(); + } else { + $this->map = $this->mapperElement->getImplementation(); + } + if ($this->map === null) { + $this->setError("Could not set element."); + } + } + + /** + * The heart of the matter. This is where the selector gets to decide + * on the inclusion of a file in a particular fileset. + * + * @param basedir the base directory the scan is being done from + * @param filename is the name of the file to check + * @param file is a PhingFile object the selector can use + * @return whether the file should be selected or not + */ + public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + + $this->validate(); + + // Determine file whose out-of-dateness is to be checked + $destfiles = $this->map->main($filename); + + // If filename does not match the To attribute of the mapper + // then filter it out of the files we are considering + if ($destfiles === null) { + return false; + } + // Sanity check + if (count($destfiles) !== 1 || $destfiles[0] === null) { + throw new BuildException("Invalid destination file results for " . $this->targetdir . " with filename " . $filename); + } + $destname = $destfiles[0]; + $destfile = new PhingFile($this->targetdir, $destname); + + return SelectorUtils::isOutOfDate($file, $destfile, $this->granularity); + } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/DepthSelector.php b/buildscripts/phing/classes/phing/types/selectors/DepthSelector.php new file mode 100644 index 00000000..3faafe96 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/DepthSelector.php @@ -0,0 +1,158 @@ +. + */ + +require_once 'phing/types/selectors/BaseExtendSelector.php'; + +/** + * Selector that filters files based on the how deep in the directory + * tree they are. + * + * @author Hans Lellelid (Phing) + * @author Bruce Atherton (Ant) + * @version $Revision: 1.7 $ + * @package phing.types.selectors + */ +class DepthSelector extends BaseExtendSelector { + + public $min = -1; + public $max = -1; + const MIN_KEY = "min"; + const MAX_KEY = "max"; + + public function toString() { + $buf = "{depthselector min: "; + $buf .= $this->min; + $buf .= " max: "; + $buf .= $this->max; + $buf .= "}"; + return $buf; + } + + /** + * The minimum depth below the basedir before a file is selected. + * + * @param min minimum directory levels below basedir to go + */ + public function setMin($min) { + $this->min = (int) $min; + } + + /** + * The minimum depth below the basedir before a file is selected. + * + * @param min maximum directory levels below basedir to go + */ + public function setMax($max) { + $this->max = (int) $max; + } + + /** + * When using this as a custom selector, this method will be called. + * It translates each parameter into the appropriate setXXX() call. + * + * @param parameters the complete set of parameters for this selector + */ + public function setParameters($parameters) { + parent::setParameters($parameters); + if ($parameters !== null) { + for ($i = 0, $size=count($parameters); $i < $size; $i++) { + $paramname = $parameters[$i]->getName(); + switch(strtolower($paramname)) { + case self::MIN_KEY: + $this->setMin($parameters[$i]->getValue()); + break; + case self::MAX_KEY: + $this->setMax($parameters[$i]->getValue()); + break; + + default: + $this->setError("Invalud parameter " . $paramname); + } // switch + } + } + } + + /** + * Checks to make sure all settings are kosher. In this case, it + * means that the max depth is not lower than the min depth. + */ + public function verifySettings() { + if ($this->min < 0 && $this->max < 0) { + $this->setError("You must set at least one of the min or the " . + "max levels."); + } + if ($this->max < $this->min && $this->max > -1) { + $this->setError("The maximum depth is lower than the minimum."); + } + } + + /** + * The heart of the matter. This is where the selector gets to decide + * on the inclusion of a file in a particular fileset. Most of the work + * for this selector is offloaded into SelectorUtils, a static class + * that provides the same services for both FilenameSelector and + * DirectoryScanner. + * + * @param basedir the base directory the scan is being done from + * @param filename is the name of the file to check + * @param file is a PhingFile object the selector can use + * @return whether the file should be selected or not + */ + public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + + $this->validate(); + + $depth = -1; + // If you felt daring, you could cache the basedir absolute path + $abs_base = $basedir->getAbsolutePath(); + $abs_file = $file->getAbsolutePath(); + + $tok_base = explode(DIRECTORY_SEPARATOR, $abs_base); + $tok_file = explode(DIRECTORY_SEPARATOR, $abs_file); + + for($i=0,$size=count($tok_file); $i < $size; $i++) { + $filetoken = $tok_file[$i]; + if (isset($tok_base[$i])) { + $basetoken = $tok_base[$i]; + // Sanity check. Ditch it if you want faster performance + if ($basetoken !== $filetoken) { + throw new BuildException("File " . $filename . + " does not appear within " . $abs_base . "directory"); + } + } else { // no more basepath tokens + $depth++; + if ($this->max > -1 && $depth > $this->max) { + return false; + } + } + } + if (isset($tok_base[$i + 1])) { + throw new BuildException("File " . $filename . + " is outside of " . $abs_base . "directory tree"); + } + if ($this->min > -1 && $depth < $this->min) { + return false; + } + return true; + } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/ExtendFileSelector.php b/buildscripts/phing/classes/phing/types/selectors/ExtendFileSelector.php new file mode 100644 index 00000000..84a3ee5b --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/ExtendFileSelector.php @@ -0,0 +1,43 @@ +. + */ + +require_once 'phing/types/Parameterizable.php'; +require_once 'phing/types/selectors/FileSelector.php'; + +/** + * This is the interface to be used by all custom selectors, those that are + * called through the <custom> tag. It is the amalgamation of two + * interfaces, the FileSelector and the Paramterizable interface. Note that + * you will almost certainly want the default behaviour for handling + * Parameters, so you probably want to use the BaseExtendSelector class + * as the base class for your custom selector rather than implementing + * this interface from scratch. + * + * @author Hans Lellelid (Phing) + * @author Bruce Atherton (Ant) + * @package phing.types.selectors + */ +interface ExtendFileSelector extends Parameterizable, FileSelector { + // No further methods necessary. This is just an amalgamation of two other + // interfaces. +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/ExtendSelector.php b/buildscripts/phing/classes/phing/types/selectors/ExtendSelector.php new file mode 100644 index 00000000..cc939254 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/ExtendSelector.php @@ -0,0 +1,127 @@ +. + */ + +include_once 'phing/util/StringHelper.php'; + +/** + * Selector that selects files by forwarding the request on to other classes. + * + * TODO: + * Consider adding Path (org.apache.tools.ant.types.Path) support to this class + * and to the Mappers class. See Ant versions for implimentation details. + * + * @author Bruce Atherton + * @package phing.types.selectors + */ +class ExtendSelector extends BaseSelector { + + private $classname; + private $dynselector; + private $parameters = array(); + + /** + * Sets the classname of the custom selector. + * + * @param classname is the class which implements this selector + */ + public function setClassname($classname) { + $this->classname = $classname; + } + + /** + * Instantiates the identified custom selector class. + */ + public function selectorCreate() { + if ($this->classname !== null && $this->classname !== "") { + try { + // assume it's fully qualified, import it + $cls = Phing::import($this->classname); + + // make sure class exists + if (class_exists($cls)) { + $this->dynselector = new $cls(); + } else { + $this->setError("Selector " . $this->classname . " not initialized, no such class"); + } + } catch (Exception $e) { + $this->setError("Selector " . $this->classname . " not initialized, could not create class: " . $e->getMessage()); + } + } else { + $this->setError("There is no classname specified"); + } + } + + /** + * Create new parameters to pass to custom selector. + * + * @param p The new Parameter object + */ + public function addParam(Parameter $p) { + $this->parameters[] = $p; + } + + /** + * These are errors specific to ExtendSelector only. If there are + * errors in the custom selector, it should throw a BuildException + * when isSelected() is called. + */ + public function verifySettings() { + // Creation is done here rather than in isSelected() because some + // containers may do a validation pass before running isSelected(), + // but we need to check for the existence of the created class. + if ($this->dynselector === null) { + $this->selectorCreate(); + } + + if (empty($this->classname)) { + $this->setError("The classname attribute is required"); + } elseif ($this->dynselector === null) { + $this->setError("Internal Error: The custom selector was not created"); + } elseif ( !($this->dynselector instanceof ExtendFileSelector) && (count($this->parameters) > 0)) { + $this->setError("Cannot set parameters on custom selector that does not " + . "implement ExtendFileSelector."); + } + } + + + /** + * Allows the custom selector to choose whether to select a file. This + * is also where the Parameters are passed to the custom selector, + * since we know we must have them all by now. And since we must know + * both classpath and classname, creating the class is deferred to here + * as well. + * + * @throws BuildException + */ + public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + + $this->validate(); + + if (count($this->parameters) > 0 && $this->dynselector instanceof ExtendFileSelector) { + // We know that dynselector must be non-null if no error message + $this->dynselector->setParameters($this->parameters); + } + return $this->dynselector->isSelected($basedir, $filename, $file); + } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/FileSelector.php b/buildscripts/phing/classes/phing/types/selectors/FileSelector.php new file mode 100644 index 00000000..05926c86 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/FileSelector.php @@ -0,0 +1,47 @@ +. + */ + +/** + * This is the interface to be used by all selectors. + * + * @author Hans Lellelid, hans@xmpl.org (Phing) + * @author Bruce Atherton, bruce@callenish.com (Ant) + * @package phing.types.selectors + */ +interface FileSelector { + + /** + * Method that each selector will implement to create their + * selection behaviour. If there is a problem with the setup + * of a selector, it can throw a BuildException to indicate + * the problem. + * + * @param basedir A PhingFile object for the base directory + * @param filename The name of the file to check + * @param file A PhingFile object for this filename + * @return whether the file should be selected or not + * @throws BuildException if the selector was not configured correctly + */ + public function isSelected(PhingFile $basedir, $filename, PhingFile $file); + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/FilenameSelector.php b/buildscripts/phing/classes/phing/types/selectors/FilenameSelector.php new file mode 100644 index 00000000..2315c888 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/FilenameSelector.php @@ -0,0 +1,157 @@ +. + */ + + +include_once 'phing/types/selectors/BaseExtendSelector.php'; + +/** + * Selector that filters files based on the filename. + * + * @author Hans Lellelid, hans@xmpl.org (Phing) + * @author Bruce Atherton, bruce@callenish.com (Ant) + * @package phing.types.selectors + */ +class FilenameSelector extends BaseExtendSelector { + + private $pattern = null; + private $casesensitive = true; + private $negated = false; + const NAME_KEY = "name"; + const CASE_KEY = "casesensitive"; + const NEGATE_KEY = "negate"; + + public function toString() { + $buf = "{filenameselector name: "; + $buf .= $this->pattern; + $buf .= " negate: "; + if ($this->negated) { + $buf .= "true"; + } else { + $buf .= "false"; + } + $buf .= " casesensitive: "; + if ($this->casesensitive) { + $buf .= "true"; + } else { + $buf .= "false"; + } + $buf .= "}"; + return $buf; + } + + /** + * The name of the file, or the pattern for the name, that + * should be used for selection. + * + * @param pattern the file pattern that any filename must match + * against in order to be selected. + */ + public function setName($pattern) { + $pattern = str_replace('\\', DIRECTORY_SEPARATOR, $pattern); + $pattern = str_replace('/', DIRECTORY_SEPARATOR, $pattern); + + if (StringHelper::endsWith(DIRECTORY_SEPARATOR, $pattern)) { + $pattern .= "**"; + } + $this->pattern = $pattern; + } + + /** + * Whether to ignore case when checking filenames. + * + * @param casesensitive whether to pay attention to case sensitivity + */ + public function setCasesensitive($casesensitive) { + $this->casesensitive = $casesensitive; + } + + /** + * You can optionally reverse the selection of this selector, + * thereby emulating an <exclude> tag, by setting the attribute + * negate to true. This is identical to surrounding the selector + * with <not></not>. + * + * @param negated whether to negate this selection + */ + public function setNegate($negated) { + $this->negated = $negated; + } + + /** + * When using this as a custom selector, this method will be called. + * It translates each parameter into the appropriate setXXX() call. + * + * @param array $parameters the complete set of parameters for this selector + */ + public function setParameters($parameters) { + parent::setParameters($parameters); + if ($parameters !== null) { + for ($i=0, $len=count($parameters); $i < $len; $i++) { + $paramname = $parameters[$i]->getName(); + switch(strtolower($paramname)) { + case self::NAME_KEY: + $this->setName($parameters[$i]->getValue()); + break; + case self::CASE_KEY: + $this->setCasesensitive($parameters[$i]->getValue()); + break; + case self::NEGATE_KEY: + $this->setNegate($parameters[$i]->getValue()); + break; + default: + $this->setError("Invalid parameter " . $paramname); + } + } // for each param + } // if params + } + + /** + * Checks to make sure all settings are kosher. In this case, it + * means that the name attribute has been set. + * + */ + public function verifySettings() { + if ($this->pattern === null) { + $this->setError("The name attribute is required"); + } + } + + /** + * The heart of the matter. This is where the selector gets to decide + * on the inclusion of a file in a particular fileset. Most of the work + * for this selector is offloaded into SelectorUtils, a static class + * that provides the same services for both FilenameSelector and + * DirectoryScanner. + * + * @param basedir the base directory the scan is being done from + * @param filename is the name of the file to check + * @param file is a PhingFile object the selector can use + * @return whether the file should be selected or not + */ + public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + $this->validate(); + return (SelectorUtils::matchPath($this->pattern, $filename, $this->casesensitive) + === !($this->negated)); + } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/MajoritySelector.php b/buildscripts/phing/classes/phing/types/selectors/MajoritySelector.php new file mode 100644 index 00000000..19e0fb76 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/MajoritySelector.php @@ -0,0 +1,92 @@ +. + */ + + +/** + * This selector is here just to shake up your thinking a bit. Don't get + * too caught up in boolean, there are other ways you can evaluate a + * collection of selectors. This one takes a vote of the selectors it + * contains, and majority wins. You could also have an "all-but-one" + * selector, a "weighted-average" selector, and so on. These are left + * as exercises for the reader (as are the usecases where this would + * be necessary). + * + * @author Hans Lellelid (Phing) + * @author Bruce Atherton (Ant) + * @package phing.types.selectors + */ +class MajoritySelector extends BaseSelectorContainer { + + private $allowtie = true; + + public function toString() { + $buf = ""; + if ($this->hasSelectors()) { + $buf .= "{majorityselect: "; + $buf .= parent::toString(); + $buf .= "}"; + } + return $buf; + } + + public function setAllowtie($tiebreaker) { + $this->allowtie = $tiebreaker; + } + + /** + * Returns true (the file is selected) if most of the other selectors + * agree. In case of a tie, go by the allowtie setting. That defaults + * to true, meaning in case of a tie, the file is selected. + * + * @param basedir the base directory the scan is being done from + * @param filename is the name of the file to check + * @param file is a PhingFile object for the filename that the selector + * can use + * @return whether the file should be selected or not + */ + public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + + $this->validate(); + + $yesvotes = 0; + $novotes = 0; + + $selectors = $this->selectorElements(); + for($i=0,$size=count($selectors); $i < $size; $i++) { + $result = $selectors[$i]->isSelected($basedir,$filename,$file); + if ($result) { + $yesvotes = $yesvotes + 1; + } else { + $novotes = $novotes + 1; + } + } + if ($yesvotes > $novotes) { + return true; + } + else if ($novotes > $yesvotes) { + return false; + } + // At this point, we know we have a tie. + return $this->allowtie; + } +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/NoneSelector.php b/buildscripts/phing/classes/phing/types/selectors/NoneSelector.php new file mode 100644 index 00000000..844078a5 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/NoneSelector.php @@ -0,0 +1,71 @@ +. + */ + +require_once 'phing/types/selectors/BaseSelectorContainer.php'; + +/** + * This selector has a collection of other selectors. All of those selectors + * must refuse to select a file before the file is considered selected by + * this selector. + * + * @author Hans Lellelid + * @author Bruce Atherton (Ant) + * @package phing.types.selectors + */ +class NoneSelector extends BaseSelectorContainer { + + public function toString() { + $buf = ""; + if ($this->hasSelectors()) { + $buf .= "{noneselect: "; + $buf .= parent::toString(); + $buf .= "}"; + } + return $buf; + } + + /** + * Returns true (the file is selected) only if all other selectors + * agree that the file should not be selected. + * + * @param basedir the base directory the scan is being done from + * @param filename is the name of the file to check + * @param file is a java.io.File object for the filename that the selector + * can use + * @return whether the file should be selected or not + */ + public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + + $this->validate(); + + $selectors = $this->selectorElements(); + + for($i=0,$size=count($selectors); $i < $size; $i++) { + $result = $selectors[$i]->isSelected($basedir, $filename, $file); + if ($result) { + return false; + } + } + return true; + } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/NotSelector.php b/buildscripts/phing/classes/phing/types/selectors/NotSelector.php new file mode 100644 index 00000000..90237084 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/NotSelector.php @@ -0,0 +1,59 @@ +. + */ + +require_once 'phing/types/selectors/NoneSelector.php'; + +/** + * This selector has one other selectors whose meaning it inverts. It + * actually relies on NoneSelector for its implementation of the + * isSelected() method, but it adds a check to ensure there is only one + * other selector contained within. + * + * @author Hans Lellelid (Phing) + * @author Bruce Atherton (Ant) + * @package phing.types.selectors + */ +class NotSelector extends NoneSelector { + + public function toString() { + $buf = ""; + if ($this->hasSelectors()) { + $buf .= "{notselect: "; + $buf .= parent::toString(); + $buf .= "}"; + } + return $buf; + } + + /** + * Makes sure that there is only one entry, sets an error message if + * not. + */ + public function verifySettings() { + if ($this->selectorCount() != 1) { + $this->setError("One and only one selector is allowed within the " . + " tag"); + } + } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/OrSelector.php b/buildscripts/phing/classes/phing/types/selectors/OrSelector.php new file mode 100644 index 00000000..6a8778fa --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/OrSelector.php @@ -0,0 +1,72 @@ +. + */ + +require_once 'phing/types/selectors/BaseSelectorContainer.php'; + +/** + * This selector has a collection of other selectors, any of which have to + * select a file in order for this selector to select it. + * + * @author Hans Lellelid (Phing) + * @author Bruce Atherton (Ant) + * @package phing.types.selectors + */ +class OrSelector extends BaseSelectorContainer { + + public function toString() { + $buf = ""; + if ($this->hasSelectors()) { + $buf .= "{orselect: "; + $buf .= parent::toString(); + $buf .= "}"; + } + return $buf; + } + + /** + * Returns true (the file is selected) if any of the other selectors + * agree that the file should be selected. + * + * @param basedir the base directory the scan is being done from + * @param filename the name of the file to check + * @param file a PhingFile object for the filename that the selector + * can use + * @return boolean Whether the file should be selected or not + */ + public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + + $this->validate(); + + $selectors = $this->selectorElements(); + + // First, check that all elements are correctly configured + + for($i=0,$size=count($selectors); $i < $size; $i++) { + $result = $selectors[$i]->isSelected($basedir, $filename, $file); + if ($result) { + return true; + } + } + return false; + } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/PresentSelector.php b/buildscripts/phing/classes/phing/types/selectors/PresentSelector.php new file mode 100644 index 00000000..f5f4c880 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/PresentSelector.php @@ -0,0 +1,154 @@ +. + */ + +/** + * Selector that filters files based on whether they appear in another + * directory tree. It can contain a mapper element, so isn't available + * as an ExtendSelector (since those parameters can't hold other + * elements). + * + * @author Hans Lellelid (Phing) + * @author Bruce Atherton (Ant) + * @package phing.types.selectors + */ +class PresentSelector extends BaseSelector { + + private $targetdir = null; + private $mapperElement = null; + private $map = null; + private $destmustexist = true; + private static $filePresence = array("srconly", "both"); + + public function toString() { + $buf = "{presentselector targetdir: "; + if ($this->targetdir === null) { + $buf .= "NOT YET SET"; + } else { + $buf .= $this->targetdir->getName(); + } + $buf .= " present: "; + if ($this->destmustexist) { + $buf .= "both"; + } else { + $buf .= "srconly"; + } + if ($this->map !== null) { + $buf .= $this->map->toString(); + } elseif ($this->mapperElement !== null) { + $buf .= $this->mapperElement->toString(); + } + $buf .= "}"; + return $buf; + } + + /** + * The name of the file or directory which is checked for matching + * files. + * + * @param targetdir the directory to scan looking for matching files. + */ + public function setTargetdir(PhingFile $targetdir) { + $this->targetdir = $targetdir; + } + + /** + * Defines the FileNameMapper to use (nested mapper element). + * @throws BuildException + */ + public function createMapper() { + if ($this->mapperElement !== null) { + throw new BuildException("Cannot define more than one mapper"); + } + $this->mapperElement = new Mapper($this->getProject()); + return $this->mapperElement; + } + + + /** + * This sets whether to select a file if its dest file is present. + * It could be a negate boolean, but by doing things + * this way, we get some documentation on how the system works. + * A user looking at the documentation should clearly understand + * that the ONLY files whose presence is being tested are those + * that already exist in the source directory, hence the lack of + * a destonly option. + * + * @param string $fp An attribute set to either srconlyboth. + */ + public function setPresent($fp) { + $idx = array_search($fp, self::$filePresence, true); + if ( $idx === 0 ) { + $this->destmustexist = false; + } + } + + /** + * Checks to make sure all settings are kosher. In this case, it + * means that the targetdir attribute has been set and we have a mapper. + */ + public function verifySettings() { + if ($this->targetdir === null) { + $this->setError("The targetdir attribute is required."); + } + if ($this->mapperElement === null) { + $this->map = new IdentityMapper(); + } else { + $this->map = $this->mapperElement->getImplementation(); + } + if ($this->map === null) { + $this->setError("Could not set element."); + } + } + + /** + * The heart of the matter. This is where the selector gets to decide + * on the inclusion of a file in a particular fileset. + * + * @param basedir the base directory the scan is being done from + * @param filename is the name of the file to check + * @param file is a PhingFile object the selector can use + * @return whether the file should be selected or not + */ + public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + + $this->validate(); + + // Determine file whose existence is to be checked + $destfiles = $this->map->main($filename); + // If filename does not match the To attribute of the mapper + // then filter it out of the files we are considering + if ($destfiles === null) { + return false; + } + // Sanity check + if (count($destfiles) !== 1 || $destfiles[0] === null) { + throw new BuildException("Invalid destination file results for " + . $this->targetdir . " with filename " . $filename); + } + $destname = $destfiles[0]; + $destfile = new PhingFile($this->targetdir, $destname); + return $destfile->exists() === $this->destmustexist; + } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/SelectSelector.php b/buildscripts/phing/classes/phing/types/selectors/SelectSelector.php new file mode 100644 index 00000000..a7644447 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/SelectSelector.php @@ -0,0 +1,124 @@ +. + */ + +require_once 'phing/types/selectors/AndSelector.php'; + +/** + * This selector just holds one other selector and forwards all + * requests to it. It exists so that there is a single selector + * type that can exist outside of any targets, as an element of + * project. It overrides all of the reference stuff so that it + * works as expected. Note that this is the only selector you + * can reference. + * + * @author Hans Lellelid (Phing) + * @author Bruce Atherton (Ant) + * @version $Revision: 1.6 $ + * @package phing.types.selectors + */ +class SelectSelector extends AndSelector { + + public function toString() { + $buf = ""; + if ($this->hasSelectors()) { + $buf .= "{select: "; + $buf .= parent::toString(); + $buf .= "}"; + } + return $buf; + } + + /** + * Performs the check for circular references and returns the + * referenced Selector. + */ + private function getRef() { + $o = $this->getCheckedRef(get_class($this), "SelectSelector"); + return $o; + } + + /** + * Indicates whether there are any selectors here. + */ + public function hasSelectors() { + if ($this->isReference()) { + return $this->getRef()->hasSelectors(); + } + return parent::hasSelectors(); + } + + /** + * Gives the count of the number of selectors in this container + */ + public function selectorCount() { + if ($this->isReference()) { + return $this->getRef()->selectorCount(); + } + return parent::selectorCount(); + } + + /** + * Returns the set of selectors as an array. + */ + public function getSelectors(Project $p) { + if ($this->isReference()) { + return $this->getRef()->getSelectors($p); + } + return parent::getSelectors($p); + } + + /** + * Returns an enumerator for accessing the set of selectors. + */ + public function selectorElements() { + if ($this->isReference()) { + return $this->getRef()->selectorElements(); + } + return parent::selectorElements(); + } + + /** + * Add a new selector into this container. + * + * @param selector the new selector to add + * @return the selector that was added + */ + public function appendSelector(FileSelector $selector) { + if ($this->isReference()) { + throw $this->noChildrenAllowed(); + } + parent::appendSelector($selector); + } + + /** + * Makes sure that there is only one entry, sets an error message if + * not. + */ + public function verifySettings() { + if ($this->selectorCount() != 1) { + $this->setError("One and only one selector is allowed within the " + . " tag"); + } + } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/SelectorContainer.php b/buildscripts/phing/classes/phing/types/selectors/SelectorContainer.php new file mode 100644 index 00000000..4a73b113 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/SelectorContainer.php @@ -0,0 +1,141 @@ +. + */ + + +/** + * This is the interface for selectors that can contain other selectors. + * + * @author Bruce Atherton + * @package phing.types.selectors + */ +interface SelectorContainer { + + /** + * Indicates whether there are any selectors here. + * + * @return whether any selectors are in this container + */ + public function hasSelectors(); + + /** + * Gives the count of the number of selectors in this container + * + * @return the number of selectors in this container + */ + public function selectorCount(); + + /** + * Returns a *copy* of the set of selectors as an array. + * + * @return an array of selectors in this container + */ + public function getSelectors(Project $p); + + /** + * Returns an array for accessing the set of selectors. + * + * @return an enumerator that goes through each of the selectors + */ + public function selectorElements(); + + /** + * Add a new selector into this container. + * + * @param selector the new selector to add + * @return the selector that was added + */ + public function appendSelector(FileSelector $selector); + + /* Methods below all add specific selectors */ + + /** + * add a "Select" selector entry on the selector list + */ + public function createSelector(); + + /** + * add an "And" selector entry on the selector list + */ + public function createAnd(); + + /** + * add an "Or" selector entry on the selector list + */ + public function createOr(); + + /** + * add a "Not" selector entry on the selector list + */ + public function createNot(); + + /** + * add a "None" selector entry on the selector list + */ + public function createNone(); + + /** + * add a majority selector entry on the selector list + */ + public function createMajority(); + + /** + * add a selector date entry on the selector list + */ + public function createDate(); + + /** + * add a selector size entry on the selector list + */ + public function createSize(); + + /** + * add a selector filename entry on the selector list + */ + public function createFilename(); + + /** + * add an extended selector entry on the selector list + */ + public function createCustom(); + + /** + * add a contains selector entry on the selector list + */ + public function createContains(); + + /** + * add a present selector entry on the selector list + */ + public function createPresent(); + + /** + * add a depth selector entry on the selector list + */ + public function createDepth(); + + /** + * add a depends selector entry on the selector list + */ + public function createDepend(); + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/SelectorScanner.php b/buildscripts/phing/classes/phing/types/selectors/SelectorScanner.php new file mode 100644 index 00000000..f5bb898a --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/SelectorScanner.php @@ -0,0 +1,55 @@ +. + */ + + +/** + * An interface used to describe the actions required by any type of + * directory scanner that supports Selecters. + * + * @author Hans Lellelid (Phing) + * @author Bruce Atherton (Ant) + * @package phing.types.selectors + */ +interface SelectorScanner { + + /** + * Sets the selectors the scanner should use. + * + * @param selectors the list of selectors + */ + public function setSelectors($selectors); + + /** + * Directories which were selected out of a scan. + * + * @param selectors list selector objects + */ + public function getDeselectedDirectories(); + + /** + * Files which were selected out of a scan. + * + * @param selectors list selector objects + */ + public function getDeselectedFiles(); + +} diff --git a/buildscripts/phing/classes/phing/types/selectors/SelectorUtils.php b/buildscripts/phing/classes/phing/types/selectors/SelectorUtils.php new file mode 100644 index 00000000..87247e97 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/SelectorUtils.php @@ -0,0 +1,440 @@ +. + */ + +include_once 'phing/util/StringHelper.php'; + +/** + *

        This is a utility class used by selectors and DirectoryScanner. The + * functionality more properly belongs just to selectors, but unfortunately + * DirectoryScanner exposed these as protected methods. Thus we have to + * support any subclasses of DirectoryScanner that may access these methods. + *

        + *

        This is a Singleton.

        + * + * @author Hans Lellelid, hans@xmpl.org (Phing) + * @author Arnout J. Kuiper, ajkuiper@wxs.nl (Ant) + * @author Magesh Umasankar + * @author Bruce Atherton, bruce@callenish.com (Ant) + * @package phing.types.selectors + */ +class SelectorUtils { + + private static $instance; + + /** + * Retrieves the instance of the Singleton. + */ + public function getInstance() { + if (!isset(self::$instance)) { + self::$instance = new SelectorUtils(); + } + return self::$instance; + } + + /** + * Tests whether or not a given path matches the start of a given + * pattern up to the first "**". + *

        + * This is not a general purpose test and should only be used if you + * can live with false positives. For example, pattern=**\a + * and str=b will yield true. + * + * @param pattern The pattern to match against. Must not be + * null. + * @param str The path to match, as a String. Must not be + * null. + * @param isCaseSensitive Whether or not matching should be performed + * case sensitively. + * + * @return whether or not a given path matches the start of a given + * pattern up to the first "**". + */ + public function matchPatternStart($pattern, $str, $isCaseSensitive = true) { + + // When str starts with a DIRECTORY_SEPARATOR, pattern has to start with a + // DIRECTORY_SEPARATOR. + // When pattern starts with a DIRECTORY_SEPARATOR, str has to start with a + // DIRECTORY_SEPARATOR. + if (StringHelper::startsWith(DIRECTORY_SEPARATOR, $str) !== + StringHelper::startsWith(DIRECTORY_SEPARATOR, $pattern)) { + return false; + } + + $patDirs = explode(DIRECTORY_SEPARATOR, $pattern); + $strDirs = explode(DIRECTORY_SEPARATOR, $str); + + $patIdxStart = 0; + $patIdxEnd = count($patDirs)-1; + $strIdxStart = 0; + $strIdxEnd = count($strDirs)-1; + + // up to first '**' + while ($patIdxStart <= $patIdxEnd && $strIdxStart <= $strIdxEnd) { + $patDir = $patDirs[$patIdxStart]; + if ($patDir == "**") { + break; + } + if (!self::match($patDir, $strDirs[$strIdxStart], $isCaseSensitive)) { + return false; + } + $patIdxStart++; + $strIdxStart++; + } + + if ($strIdxStart > $strIdxEnd) { + // String is exhausted + return true; + } elseif ($patIdxStart > $patIdxEnd) { + // String not exhausted, but pattern is. Failure. + return false; + } else { + // pattern now holds ** while string is not exhausted + // this will generate false positives but we can live with that. + return true; + } + } + + /** + * Tests whether or not a given path matches a given pattern. + * + * @param pattern The pattern to match against. Must not be + * null. + * @param str The path to match, as a String. Must not be + * null. + * @param isCaseSensitive Whether or not matching should be performed + * case sensitively. + * + * @return true if the pattern matches against the string, + * or false otherwise. + */ + public function matchPath($pattern, $str, $isCaseSensitive = true) { + + // When str starts with a DIRECTORY_SEPARATOR, pattern has to start with a + // DIRECTORY_SEPARATOR. + // When pattern starts with a DIRECTORY_SEPARATOR, str has to start with a + // DIRECTORY_SEPARATOR. + if (StringHelper::startsWith(DIRECTORY_SEPARATOR, $str) !== + StringHelper::startsWith(DIRECTORY_SEPARATOR, $pattern)) { + return false; + } + + $patDirs = explode(DIRECTORY_SEPARATOR, $pattern); + $strDirs = explode(DIRECTORY_SEPARATOR, $str); + + $patIdxStart = 0; + $patIdxEnd = count($patDirs)-1; + $strIdxStart = 0; + $strIdxEnd = count($strDirs)-1; + + // up to first '**' + while ($patIdxStart <= $patIdxEnd && $strIdxStart <= $strIdxEnd) { + $patDir = $patDirs[$patIdxStart]; + if ($patDir == "**") { + break; + } + if (!self::match($patDir, $strDirs[$strIdxStart], $isCaseSensitive)) { + return false; + } + $patIdxStart++; + $strIdxStart++; + } + if ($strIdxStart > $strIdxEnd) { + // String is exhausted + for ($i=$patIdxStart; $i <= $patIdxEnd; $i++) { + if ($patDirs[$i] != "**") { + return false; + } + } + return true; + } elseif ($patIdxStart > $patIdxEnd) { + // String not exhausted, but pattern is. Failure. + return false; + } + + // up to last '**' + while ($patIdxStart <= $patIdxEnd && $strIdxStart <= $strIdxEnd) { + $patDir = $patDirs[$patIdxEnd]; + if ($patDir == "**") { + break; + } + if (!self::match($patDir, $strDirs[$strIdxEnd], $isCaseSensitive)) { + return false; + } + $patIdxEnd--; + $strIdxEnd--; + } + + if ($strIdxStart > $strIdxEnd) { + // String is exhausted + for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { + if ($patDirs[$i] != "**") { + return false; + } + } + return true; + } + + while ($patIdxStart != $patIdxEnd && $strIdxStart <= $strIdxEnd) { + $patIdxTmp = -1; + for ($i = $patIdxStart+1; $i <= $patIdxEnd; $i++) { + if ($patDirs[$i] == "**") { + $patIdxTmp = $i; + break; + } + } + if ($patIdxTmp == $patIdxStart+1) { + // '**/**' situation, so skip one + $patIdxStart++; + continue; + } + // Find the pattern between padIdxStart & padIdxTmp in str between + // strIdxStart & strIdxEnd + $patLength = ($patIdxTmp-$patIdxStart-1); + $strLength = ($strIdxEnd-$strIdxStart+1); + $foundIdx = -1; + + //strLoop: (start of outer loop) + for ($i=0; $i <= $strLength - $patLength; $i++) { + for ($j = 0; $j < $patLength; $j++) { + $subPat = $patDirs[$patIdxStart+$j+1]; + $subStr = $strDirs[$strIdxStart+$i+$j]; + if (!self::match($subPat, $subStr, $isCaseSensitive)) { + continue 2; // continue up two levels (to strLoop:) + } + } + $foundIdx = $strIdxStart+$i; // only reached if all sub patterns matched + break; + } + + if ($foundIdx == -1) { + return false; + } + + $patIdxStart = $patIdxTmp; + $strIdxStart = $foundIdx + $patLength; + } + + for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { + if ($patDirs[$i] != "**") { + return false; + } + } + + return true; + } + + /** + * Tests whether or not a string matches against a pattern. + * The pattern may contain two special characters:
        + * '*' means zero or more characters
        + * '?' means one and only one character + * + * @param pattern The pattern to match against. + * Must not be null. + * @param str The string which must be matched against the pattern. + * Must not be null. + * @param isCaseSensitive Whether or not matching should be performed + * case sensitively. + * + * + * @return true if the string matches against the pattern, + * or false otherwise. + */ + public function match($pattern, $str, $isCaseSensitive = true) { + + $patArr = StringHelper::toCharArray($pattern); + $strArr = StringHelper::toCharArray($str); + $patIdxStart = 0; + $patIdxEnd = count($patArr)-1; + $strIdxStart = 0; + $strIdxEnd = count($strArr)-1; + + $containsStar = false; + for ($i = 0, $size=count($patArr); $i < $size; $i++) { + if ($patArr[$i] == '*') { + $containsStar = true; + break; + } + } + + if (!$containsStar) { + // No '*'s, so we make a shortcut + if ($patIdxEnd != $strIdxEnd) { + return false; // Pattern and string do not have the same size + } + for ($i = 0; $i <= $patIdxEnd; $i++) { + $ch = $patArr[$i]; + if ($ch != '?') { + if ($isCaseSensitive && $ch !== $strArr[$i]) { + return false;// Character mismatch + } + if (!$isCaseSensitive && strtoupper($ch) !== + strtoupper($strArr[$i])) { + return false; // Character mismatch + } + } + } + return true; // String matches against pattern + } + + if ($patIdxEnd == 0) { + return true; // Pattern contains only '*', which matches anything + } + + // Process characters before first star + while(($ch = $patArr[$patIdxStart]) != '*' && $strIdxStart <= $strIdxEnd) { + if ($ch != '?') { + if ($isCaseSensitive && $ch !== $strArr[$strIdxStart]) { + return false;// Character mismatch + } + if (!$isCaseSensitive && strtoupper($ch) !== + strtoupper($strArr[$strIdxStart])) { + return false;// Character mismatch + } + } + $patIdxStart++; + $strIdxStart++; + } + + if ($strIdxStart > $strIdxEnd) { + // All characters in the string are used. Check if only '*'s are + // left in the pattern. If so, we succeeded. Otherwise failure. + for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { + if ($patArr[$i] != '*') { + return false; + } + } + return true; + } + + // Process characters after last star + while(($ch = $patArr[$patIdxEnd]) != '*' && $strIdxStart <= $strIdxEnd) { + if ($ch != '?') { + if ($isCaseSensitive && $ch !== $strArr[$strIdxEnd]) { + return false;// Character mismatch + } + if (!$isCaseSensitive && strtoupper($ch) !== + strtoupper($strArr[$strIdxEnd])) { + return false;// Character mismatch + } + } + $patIdxEnd--; + $strIdxEnd--; + } + if ($strIdxStart > $strIdxEnd) { + // All characters in the string are used. Check if only '*'s are + // left in the pattern. If so, we succeeded. Otherwise failure. + for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { + if ($patArr[$i] != '*') { + return false; + } + } + return true; + } + + // process pattern between stars. padIdxStart and patIdxEnd point + // always to a '*'. + while ($patIdxStart !== $patIdxEnd && $strIdxStart <= $strIdxEnd) { + $patIdxTmp = -1; + for ($i = $patIdxStart+1; $i <= $patIdxEnd; $i++) { + if ($patArr[$i] == '*') { + $patIdxTmp = $i; + break; + } + } + if ($patIdxTmp === $patIdxStart + 1) { + // Two stars next to each other, skip the first one. + $patIdxStart++; + continue; + } + // Find the pattern between padIdxStart & padIdxTmp in str between + // strIdxStart & strIdxEnd + $patLength = ($patIdxTmp - $patIdxStart - 1); + $strLength = ($strIdxEnd - $strIdxStart + 1); + $foundIdx = -1; + + //strLoop: + for ($i = 0; $i <= $strLength - $patLength; $i++) { + for ($j = 0; $j < $patLength; $j++) { + $ch = $patArr[$patIdxStart+$j+1]; + if ($ch != '?') { + if ($isCaseSensitive && $ch !== $strArr[$strIdxStart+$i+$j]) { + continue 2; //continue to strLoop: + } + if (!$isCaseSensitive && strtoupper($ch) !== + strtoupper($strArr[$strIdxStart+$i+$j])) { + continue 2; //continue to strLoop: + } + } + } + // only reached if sub loop completed w/o invoking continue 2 + $foundIdx = $strIdxStart + $i; + break; + } + + if ($foundIdx == -1) { + return false; + } + + $patIdxStart = $patIdxTmp; + $strIdxStart = $foundIdx + $patLength; + } + + // All characters in the string are used. Check if only '*'s are left + // in the pattern. If so, we succeeded. Otherwise failure. + for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { + if ($patArr[$i] != '*') { + return false; + } + } + return true; + } + + /** + * Returns dependency information on these two files. If src has been + * modified later than target, it returns true. If target doesn't exist, + * it likewise returns true. Otherwise, target is newer than src and + * is not out of date, thus the method returns false. It also returns + * false if the src file doesn't even exist, since how could the + * target then be out of date. + * + * @param PhingFile $src the original file + * @param PhingFile $target the file being compared against + * @param int $granularity the amount in seconds of slack we will give in + * determining out of dateness + * @return whether the target is out of date + */ + public function isOutOfDate(PhingFile $src, PhingFile $target, $granularity) { + if (!$src->exists()) { + return false; + } + if (!$target->exists()) { + return true; + } + if (($src->lastModified() - $granularity) > $target->lastModified()) { + return true; + } + return false; + } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/SizeSelector.php b/buildscripts/phing/classes/phing/types/selectors/SizeSelector.php new file mode 100644 index 00000000..bbc26423 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/SizeSelector.php @@ -0,0 +1,228 @@ +. + */ + + +/** + * Selector that filters files based on their size. + * + * @author Hans Lellelid (Phing) + * @author Bruce Atherton (Ant) + * @package phing.types.selectors + */ +class SizeSelector extends BaseExtendSelector { + + private $size = -1; + private $multiplier = 1; + private $sizelimit = -1; + private $cmp = 2; + const SIZE_KEY = "value"; + const UNITS_KEY = "units"; + const WHEN_KEY = "when"; + + private static $sizeComparisons = array("less", "more", "equal"); + private static $byteUnits = array("K", "k", "kilo", "KILO", + "Ki", "KI", "ki", "kibi", "KIBI", + "M", "m", "mega", "MEGA", + "Mi", "MI", "mi", "mebi", "MEBI", + "G", "g", "giga", "GIGA", + "Gi", "GI", "gi", "gibi", "GIBI", + "T", "t", "tera", "TERA", + /* You wish! */ "Ti", "TI", "ti", "tebi", "TEBI" + ); + + public function toString() { + $buf = "{sizeselector value: "; + $buf .= $this->sizelimit; + $buf .= "compare: "; + if ($this->cmp === 0) { + $buf .= "less"; + } elseif ($this->cmp === 1) { + $buf .= "more"; + } else { + $buf .= "equal"; + } + $buf .= "}"; + return $buf; + } + + /** + * A size selector needs to know what size to base its selecting on. + * This will be further modified by the multiplier to get an + * actual size limit. + * + * @param size the size to select against expressed in units + */ + public function setValue($size) { + $this->size = $size; + if (($this->multiplier !== 0) && ($this->size > -1)) { + $this->sizelimit = $size * $this->multiplier; + } + } + + /** + * Sets the units to use for the comparison. This is a little + * complicated because common usage has created standards that + * play havoc with capitalization rules. Thus, some people will + * use "K" for indicating 1000's, when the SI standard calls for + * "k". Others have tried to introduce "K" as a multiple of 1024, + * but that falls down when you reach "M", since "m" is already + * defined as 0.001. + *

        + * To get around this complexity, a number of standards bodies + * have proposed the 2^10 standard, and at least one has adopted + * it. But we are still left with a populace that isn't clear on + * how capitalization should work. + *

        + * We therefore ignore capitalization as much as possible. + * Completely mixed case is not possible, but all upper and lower + * forms are accepted for all long and short forms. Since we have + * no need to work with the 0.001 case, this practice works here. + *

        + * This function translates all the long and short forms that a + * unit prefix can occur in and translates them into a single + * multiplier. + * + * @param $units The units to compare the size to. + * @return void + */ + public function setUnits($units) { + $i = array_search($units, self::$byteUnits, true); + if ($i === false) $i = -1; // make it java-like + + $this->multiplier = 0; + if (($i > -1) && ($i < 4)) { + $this->multiplier = 1000; + } elseif (($i > 3) && ($i < 9)) { + $this->multiplier = 1024; + } elseif (($i > 8) && ($i < 13)) { + $this->multiplier = 1000000; + } elseif (($i > 12) && ($i < 18)) { + $this->multiplier = 1048576; + } elseif (($i > 17) && ($i < 22)) { + $this->multiplier = 1000000000; + } elseif (($i > 21) && ($i < 27)) { + $this->multiplier = 1073741824; + } elseif (($i > 26) && ($i < 31)) { + $this->multiplier = 1000000000000; + } elseif (($i > 30) && ($i < 36)) { + $this->multiplier = 1099511627776; + } + if (($this->multiplier > 0) && ($this->size > -1)) { + $this->sizelimit = $this->size * $this->multiplier; + } + } + + /** + * This specifies when the file should be selected, whether it be + * when the file matches a particular size, when it is smaller, + * or whether it is larger. + * + * @param cmp The comparison to perform, an EnumeratedAttribute + */ + public function setWhen($cmp) { + $c = array_search($cmp, self::$sizeComparisons, true); + if ($c !== false) { + $this->cmp = $c; + } + } + + /** + * When using this as a custom selector, this method will be called. + * It translates each parameter into the appropriate setXXX() call. + * + * @param parameters the complete set of parameters for this selector + */ + public function setParameters($parameters) { + parent::setParameters($parameters); + if ($parameters !== null) { + for ($i = 0, $size=count($parameters); $i < $size; $i++) { + $paramname = $parameters[$i]->getName(); + switch(strtolower($paramname)) { + case self::SIZE_KEY: + try { + $this->setValue($parameters[$i]->getValue()); + } catch (Exception $nfe) { + $this->setError("Invalid size setting " + . $parameters[$i]->getValue()); + } + break; + case self::UNITS_KEY: + $this->setUnits($parameters[$i]->getValue()); + break; + case self::WHEN_KEY: + $this->setWhen($parameters[$i]->getValue()); + break; + default: + $this->setError("Invalid parameter " . $paramname); + } + } + } + } + + /** + *

        Checks to make sure all settings are kosher. In this case, it + * means that the size attribute has been set (to a positive value), + * that the multiplier has a valid setting, and that the size limit + * is valid. Since the latter is a calculated value, this can only + * fail due to a programming error. + *

        + *

        If a problem is detected, the setError() method is called. + *

        + */ + public function verifySettings() { + if ($this->size < 0) { + $this->setError("The value attribute is required, and must be positive"); + } elseif ($this->multiplier < 1) { + $this->setError("Invalid Units supplied, must be K,Ki,M,Mi,G,Gi,T,or Ti"); + } elseif ($this->sizelimit < 0) { + $this->setError("Internal error: Code is not setting sizelimit correctly"); + } + } + + /** + * The heart of the matter. This is where the selector gets to decide + * on the inclusion of a file in a particular fileset. + * + * @param basedir A PhingFile object for the base directory + * @param filename The name of the file to check + * @param file A PhingFile object for this filename + * @return whether the file should be selected or not + */ + public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + + $this->validate(); + + // Directory size never selected for + if ($file->isDirectory()) { + return true; + } + if ($this->cmp === 0) { + return ($file->length() < $this->sizelimit); + } elseif ($this->cmp === 1) { + return ($file->length() > $this->sizelimit); + } else { + return ($file->length() === $this->sizelimit); + } + } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/TypeSelector.php b/buildscripts/phing/classes/phing/types/selectors/TypeSelector.php new file mode 100644 index 00000000..f1532308 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/TypeSelector.php @@ -0,0 +1,113 @@ +. + */ + +require_once 'phing/types/selectors/BaseExtendSelector.php'; + +/** + * Selector that selects a certain kind of file: directory or regular file. + * + * @author Hans Lellelid (Phing) + * @author Jeff Turner (Ant) + * @version $Revision: 1.3 $ + * @package phing.types.selectors + */ +class TypeSelector extends BaseExtendSelector { + + private $type; + + /** Key to used for parameterized custom selector */ + const TYPE_KEY = "type"; + + /** Valid types */ + private static $types = array('file', 'dir'); + + /** + * @return string A string describing this object + */ + public function toString() { + $buf = "{typeselector type: " . $this->type . "}"; + return $buf; + } + + /** + * Set the type of file to require. + * @param string $type The type of file - 'file' or 'dir' + */ + public function setType($type) { + $this->type = $type; + } + + /** + * When using this as a custom selector, this method will be called. + * It translates each parameter into the appropriate setXXX() call. + * + * @param array $parameters the complete set of parameters for this selector + */ + public function setParameters($parameters) { + parent::setParameters($parameters); + if ($parameters !== null) { + for ($i = 0, $size=count($parameters); $i < $size; $i++) { + $paramname = $parameters[$i]->getName(); + if (self::TYPE_KEY == strtolower($paramname)) { + $this->setType($parameters[$i]->getValue()); + } else { + $this->setError("Invalid parameter " . $paramname); + } + } + } + } + + /** + * Checks to make sure all settings are kosher. In this case, it + * means that the pattern attribute has been set. + * + */ + public function verifySettings() { + if ($this->type === null) { + $this->setError("The type attribute is required"); + } elseif (!in_array($this->type, self::$types, true)) { + $this->setError("Invalid type specified; must be one of (" . implode(self::$types) . ")"); + } + } + + /** + * The heart of the matter. This is where the selector gets to decide + * on the inclusion of a file in a particular fileset. + * + * @param PhingFile $basedir the base directory the scan is being done from + * @param string $filename is the name of the file to check + * @param PhingFile $file is a PhingFile object the selector can use + * @return boolean Whether the file should be selected or not + */ + public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + + // throw BuildException on error + $this->validate(); + + if ($file->isDirectory()) { + return $this->type === 'dir'; + } else { + return $this->type === 'file'; + } + } + +} diff --git a/buildscripts/phing/classes/phing/util/DirectoryScanner.php b/buildscripts/phing/classes/phing/util/DirectoryScanner.php new file mode 100644 index 00000000..e04c4880 --- /dev/null +++ b/buildscripts/phing/classes/phing/util/DirectoryScanner.php @@ -0,0 +1,710 @@ +. + */ + +require_once 'phing/types/selectors/SelectorScanner.php'; +include_once 'phing/util/StringHelper.php'; +include_once 'phing/types/selectors/SelectorUtils.php'; + +/** + * Class for scanning a directory for files/directories that match a certain + * criteria. + * + * These criteria consist of a set of include and exclude patterns. With these + * patterns, you can select which files you want to have included, and which + * files you want to have excluded. + * + * The idea is simple. A given directory is recursively scanned for all files + * and directories. Each file/directory is matched against a set of include + * and exclude patterns. Only files/directories that match at least one + * pattern of the include pattern list, and don't match a pattern of the + * exclude pattern list will be placed in the list of files/directories found. + * + * When no list of include patterns is supplied, "**" will be used, which + * means that everything will be matched. When no list of exclude patterns is + * supplied, an empty list is used, such that nothing will be excluded. + * + * The pattern matching is done as follows: + * The name to be matched is split up in path segments. A path segment is the + * name of a directory or file, which is bounded by DIRECTORY_SEPARATOR + * ('/' under UNIX, '\' under Windows). + * E.g. "abc/def/ghi/xyz.php" is split up in the segments "abc", "def", "ghi" + * and "xyz.php". + * The same is done for the pattern against which should be matched. + * + * Then the segments of the name and the pattern will be matched against each + * other. When '**' is used for a path segment in the pattern, then it matches + * zero or more path segments of the name. + * + * There are special case regarding the use of DIRECTORY_SEPARATOR at + * the beginning of the pattern and the string to match: + * When a pattern starts with a DIRECTORY_SEPARATOR, the string + * to match must also start with a DIRECTORY_SEPARATOR. + * When a pattern does not start with a DIRECTORY_SEPARATOR, the + * string to match may not start with a DIRECTORY_SEPARATOR. + * When one of these rules is not obeyed, the string will not + * match. + * + * When a name path segment is matched against a pattern path segment, the + * following special characters can be used: + * '*' matches zero or more characters, + * '?' matches one character. + * + * Examples: + * + * "**\*.php" matches all .php files/dirs in a directory tree. + * + * "test\a??.php" matches all files/dirs which start with an 'a', then two + * more characters and then ".php", in a directory called test. + * + * "**" matches everything in a directory tree. + * + * "**\test\**\XYZ*" matches all files/dirs that start with "XYZ" and where + * there is a parent directory called test (e.g. "abc\test\def\ghi\XYZ123"). + * + * Case sensitivity may be turned off if necessary. By default, it is + * turned on. + * + * Example of usage: + * $ds = new DirectroyScanner(); + * $includes = array("**\*.php"); + * $excludes = array("modules\*\**"); + * $ds->SetIncludes($includes); + * $ds->SetExcludes($excludes); + * $ds->SetBasedir("test"); + * $ds->SetCaseSensitive(true); + * $ds->Scan(); + * + * print("FILES:"); + * $files = ds->GetIncludedFiles(); + * for ($i = 0; $i < count($files);$i++) { + * println("$files[$i]\n"); + * } + * + * This will scan a directory called test for .php files, but excludes all + * .php files in all directories under a directory called "modules" + * + * This class is complete preg/ereg free port of the Java class + * org.apache.tools.ant.DirectoryScanner. Even functions that use preg/ereg + * internally (like split()) are not used. Only the _fast_ string functions + * and comparison operators (=== !=== etc) are used for matching and tokenizing. + * + * @author Arnout J. Kuiper, ajkuiper@wxs.nl + * @author Magesh Umasankar, umagesh@rediffmail.com + * @author Andreas Aderhold, andi@binarycloud.com + * + * @version $Revision: 1.15 $ + * @package phing.util + */ +class DirectoryScanner implements SelectorScanner { + + /** default set of excludes */ + protected $DEFAULTEXCLUDES = array( + "**/*~", + "**/#*#", + "**/.#*", + "**/%*%", + "**/CVS", + "**/CVS/**", + "**/.cvsignore", + "**/SCCS", + "**/SCCS/**", + "**/vssver.scc", + "**/.svn", + "**/.svn/**", + "**/._*", + "**/.DS_Store", + ); + + /** The base directory which should be scanned. */ + protected $basedir; + + /** The patterns for the files that should be included. */ + protected $includes = null; + + /** The patterns for the files that should be excluded. */ + protected $excludes = null; + + /** + * The files that where found and matched at least one includes, and matched + * no excludes. + */ + protected $filesIncluded; + + /** The files that where found and did not match any includes. Trie */ + protected $filesNotIncluded; + + /** + * The files that where found and matched at least one includes, and also + * matched at least one excludes. Trie object. + */ + protected $filesExcluded; + + /** + * The directories that where found and matched at least one includes, and + * matched no excludes. + */ + protected $dirsIncluded; + + /** The directories that where found and did not match any includes. */ + protected $dirsNotIncluded; + + /** + * The files that where found and matched at least one includes, and also + * matched at least one excludes. + */ + protected $dirsExcluded; + + /** Have the vars holding our results been built by a slow scan? */ + protected $haveSlowResults = false; + + /** Should the file system be treated as a case sensitive one? */ + protected $isCaseSensitive = true; + + /** Selectors */ + protected $selectors = null; + + protected $filesDeselected; + protected $dirsDeselected; + + /** if there are no deselected files */ + protected $everythingIncluded = true; + + /** + * Does the path match the start of this pattern up to the first "**". + * This is a static mehtod and should always be called static + * + * This is not a general purpose test and should only be used if you + * can live with false positives. + * + * pattern=**\a and str=b will yield true. + * + * @param pattern the (non-null) pattern to match against + * @param str the (non-null) string (path) to match + * @param isCaseSensitive must matches be case sensitive? + * @return boolean true if matches, otherwise false + */ + function matchPatternStart($pattern, $str, $isCaseSensitive = true) { + return SelectorUtils::matchPatternStart($pattern, $str, $isCaseSensitive); + } + + /** + * Matches a path against a pattern. Static + * + * @param pattern the (non-null) pattern to match against + * @param str the (non-null) string (path) to match + * @param isCaseSensitive must a case sensitive match be done? + * + * @return true when the pattern matches against the string. + * false otherwise. + */ + function matchPath($pattern, $str, $isCaseSensitive = true) { + return SelectorUtils::matchPath($pattern, $str, $isCaseSensitive); + } + + /** + * Matches a string against a pattern. The pattern contains two special + * characters: + * '*' which means zero or more characters, + * '?' which means one and only one character. + * + * @param pattern the (non-null) pattern to match against + * @param str the (non-null) string that must be matched against the + * pattern + * + * @return boolean true when the string matches against the pattern, + * false otherwise. + * @access public + */ + function match($pattern, $str, $isCaseSensitive = true) { + return SelectorUtils::match($pattern, $str, $isCaseSensitive); + } + + /** + * Sets the basedir for scanning. This is the directory that is scanned + * recursively. All '/' and '\' characters are replaced by + * DIRECTORY_SEPARATOR + * + * @param basedir the (non-null) basedir for scanning + */ + function setBasedir($_basedir) { + $_basedir = str_replace('\\', DIRECTORY_SEPARATOR, $_basedir); + $_basedir = str_replace('/', DIRECTORY_SEPARATOR, $_basedir); + $this->basedir = $_basedir; + } + + /** + * Gets the basedir that is used for scanning. This is the directory that + * is scanned recursively. + * + * @return the basedir that is used for scanning + */ + function getBasedir() { + return $this->basedir; + } + + /** + * Sets the case sensitivity of the file system + * + * @param specifies if the filesystem is case sensitive + */ + function setCaseSensitive($_isCaseSensitive) { + $this->isCaseSensitive = ($_isCaseSensitive) ? true : false; + } + + /** + * Sets the set of include patterns to use. All '/' and '\' characters are + * replaced by DIRECTORY_SEPARATOR. So the separator used need + * not match DIRECTORY_SEPARATOR. + * + * When a pattern ends with a '/' or '\', "**" is appended. + * + * @param includes list of include patterns + */ + function setIncludes($_includes = array()) { + if (empty($_includes) || is_null($_includes)) { + $this->includes = null; + } else { + for ($i = 0; $i < count($_includes); $i++) { + $pattern = null; + $pattern = str_replace('\\', DIRECTORY_SEPARATOR, $_includes[$i]); + $pattern = str_replace('/', DIRECTORY_SEPARATOR, $pattern); + if (StringHelper::endsWith(DIRECTORY_SEPARATOR, $pattern)) { + $pattern .= "**"; + } + $this->includes[] = $pattern; + } + } + } + + /** + * Sets the set of exclude patterns to use. All '/' and '\' characters are + * replaced by File.separatorChar. So the separator used need + * not match File.separatorChar. + * + * When a pattern ends with a '/' or '\', "**" is appended. + * + * @param excludes list of exclude patterns + */ + + function setExcludes($_excludes = array()) { + if (empty($_excludes) || is_null($_excludes)) { + $this->excludes = null; + } else { + for ($i = 0; $i < count($_excludes); $i++) { + $pattern = null; + $pattern = str_replace('\\', DIRECTORY_SEPARATOR, $_excludes[$i]); + $pattern = str_replace('/', DIRECTORY_SEPARATOR, $pattern); + if (StringHelper::endsWith(DIRECTORY_SEPARATOR, $pattern)) { + $pattern .= "**"; + } + $this->excludes[] = $pattern; + } + } + } + + /** + * Scans the base directory for files that match at least one include + * pattern, and don't match any exclude patterns. + * + */ + function scan() { + + if ((empty($this->basedir)) || (!@is_dir($this->basedir))) { + return false; + } + + if ($this->includes === null) { + // No includes supplied, so set it to 'matches all' + $this->includes = array("**"); + } + if (is_null($this->excludes)) { + $this->excludes = array(); + } + + $this->filesIncluded = array(); + $this->filesNotIncluded = array(); + $this->filesExcluded = array(); + $this->dirsIncluded = array(); + $this->dirsNotIncluded = array(); + $this->dirsExcluded = array(); + $this->dirsDeselected = array(); + $this->filesDeselected = array(); + + if ($this->isIncluded("")) { + if (!$this->isExcluded("")) { + if ($this->isSelected("", $this->basedir)) { + $this->dirsIncluded[] = ""; + } else { + $this->dirsDeselected[] = ""; + } + } else { + $this->dirsExcluded[] = ""; + } + } else { + $this->dirsNotIncluded[] = ""; + } + + $this->scandir($this->basedir, "", true); + return true; + } + + /** + * Toplevel invocation for the scan. + * + * Returns immediately if a slow scan has already been requested. + */ + protected function slowScan() { + + if ($this->haveSlowResults) { + return; + } + + // copy trie object add CopyInto() method + $excl = $this->dirsExcluded; + $notIncl = $this->dirsNotIncluded; + + for ($i=0, $_i=count($excl); $i < $_i; $i++) { + if (!$this->couldHoldIncluded($excl[$i])) { + $this->scandir($this->basedir.$excl[$i], $excl[$i].DIRECTORY_SEPARATOR, false); + } + } + + for ($i=0, $_i=count($notIncl); $i < $_i; $i++) { + if (!$this->couldHoldIncluded($notIncl[$i])) { + $this->scandir($this->basedir.$notIncl[$i], $notIncl[$i].DIRECTORY_SEPARATOR, false); + } + } + + $this->haveSlowResults = true; + } + + /** + * Lists contens of a given directory and returns array with entries + * + * @param src String. Source path and name file to copy. + * + * @access public + * @return array directory entries + * @author Albert Lash, alash@plateauinnovation.com + */ + + function listDir($_dir) { + $d = dir($_dir); + $list = array(); + while($entry = $d->read()) { + if ($entry != "." && $entry != "..") { + $list[] = $entry; + } + } + $d->close(); + return $list; + } + + /** + * Scans the passed dir for files and directories. Found files and + * directories are placed in their respective collections, based on the + * matching of includes and excludes. When a directory is found, it is + * scanned recursively. + * + * @param dir the directory to scan + * @param vpath the path relative to the basedir (needed to prevent + * problems with an absolute path when using dir) + * + * @access private + * @see #filesIncluded + * @see #filesNotIncluded + * @see #filesExcluded + * @see #dirsIncluded + * @see #dirsNotIncluded + * @see #dirsExcluded + */ + private function scandir($_rootdir, $_vpath, $_fast) { + + if (!is_readable($_rootdir)) { + return; + } + + $newfiles = self::listDir($_rootdir); + + for ($i=0,$_i=count($newfiles); $i < $_i; $i++) { + + $file = $_rootdir . DIRECTORY_SEPARATOR . $newfiles[$i]; + $name = $_vpath . $newfiles[$i]; + + if (@is_dir($file)) { + if ($this->isIncluded($name)) { + if (!$this->isExcluded($name)) { + if ($this->isSelected($name, $file)) { + $this->dirsIncluded[] = $name; + if ($_fast) { + $this->scandir($file, $name.DIRECTORY_SEPARATOR, $_fast); + } + } else { + $this->everythingIncluded = false; + $this->dirsDeselected[] = $name; + if ($_fast && $this->couldHoldIncluded($name)) { + $this->scandir($file, $name.DIRECTORY_SEPARATOR, $_fast); + } + } + } else { + $this->everythingIncluded = false; + $this->dirsExcluded[] = $name; + if ($_fast && $this->couldHoldIncluded($name)) { + $this->scandir($file, $name.DIRECTORY_SEPARATOR, $_fast); + } + } + } else { + $this->everythingIncluded = false; + $this->dirsNotIncluded[] = $name; + if ($_fast && $this->couldHoldIncluded($name)) { + $this->scandir($file, $name.DIRECTORY_SEPARATOR, $_fast); + } + } + + if (!$_fast) { + $this->scandir($file, $name.DIRECTORY_SEPARATOR, $_fast); + } + + } elseif (@is_file($file)) { + if ($this->isIncluded($name)) { + if (!$this->isExcluded($name)) { + if ($this->isSelected($name, $file)) { + $this->filesIncluded[] = $name; + } else { + $this->everythingIncluded = false; + $this->filesDeselected[] = $name; + } + } else { + $this->everythingIncluded = false; + $this->filesExcluded[] = $name; + } + } else { + $this->everythingIncluded = false; + $this->filesNotIncluded[] = $name; + } + } + } + } + + /** + * Tests whether a name matches against at least one include pattern. + * + * @param name the name to match + * @return true when the name matches against at least one + * include pattern, false otherwise. + */ + protected function isIncluded($_name) { + for ($i=0, $_i=count($this->includes); $i < $_i; $i++) { + if (DirectoryScanner::matchPath($this->includes[$i], $_name, $this->isCaseSensitive)) { + return true; + } + } + return false; + } + + /** + * Tests whether a name matches the start of at least one include pattern. + * + * @param name the name to match + * @return true when the name matches against at least one + * include pattern, false otherwise. + */ + protected function couldHoldIncluded($_name) { + for ($i = 0; $i < count($this->includes); $i++) { + if (DirectoryScanner::matchPatternStart($this->includes[$i], $_name, $this->isCaseSensitive)) { + return true; + } + } + return false; + } + + /** + * Tests whether a name matches against at least one exclude pattern. + * + * @param name the name to match + * @return true when the name matches against at least one + * exclude pattern, false otherwise. + */ + protected function isExcluded($_name) { + for ($i = 0; $i < count($this->excludes); $i++) { + if (DirectoryScanner::matchPath($this->excludes[$i], $_name, $this->isCaseSensitive)) { + return true; + } + } + return false; + } + + /** + * Get the names of the files that matched at least one of the include + * patterns, and matched none of the exclude patterns. + * The names are relative to the basedir. + * + * @return the names of the files + */ + function getIncludedFiles() { + return $this->filesIncluded; + } + + /** + * Get the names of the files that matched at none of the include patterns. + * The names are relative to the basedir. + * + * @return the names of the files + */ + function getNotIncludedFiles() { + $this->slowScan(); + return $this->filesNotIncluded; + } + + /** + * Get the names of the files that matched at least one of the include + * patterns, an matched also at least one of the exclude patterns. + * The names are relative to the basedir. + * + * @return the names of the files + */ + + function getExcludedFiles() { + $this->slowScan(); + return $this->filesExcluded; + } + + /** + *

        Returns the names of the files which were selected out and + * therefore not ultimately included.

        + * + *

        The names are relative to the base directory. This involves + * performing a slow scan if one has not already been completed.

        + * + * @return the names of the files which were deselected. + * + * @see #slowScan + */ + public function getDeselectedFiles() { + $this->slowScan(); + return $this->filesDeselected; + } + + /** + * Get the names of the directories that matched at least one of the include + * patterns, an matched none of the exclude patterns. + * The names are relative to the basedir. + * + * @return the names of the directories + */ + + function getIncludedDirectories() { + return $this->dirsIncluded; + } + + /** + * Get the names of the directories that matched at none of the include + * patterns. + * The names are relative to the basedir. + * + * @return the names of the directories + */ + function getNotIncludedDirectories() { + $this->slowScan(); + return $this->dirsNotIncluded; + } + + /** + *

        Returns the names of the directories which were selected out and + * therefore not ultimately included.

        + * + *

        The names are relative to the base directory. This involves + * performing a slow scan if one has not already been completed.

        + * + * @return the names of the directories which were deselected. + * + * @see #slowScan + */ + public function getDeselectedDirectories() { + $this->slowScan(); + return $this->dirsDeselected; + } + + /** + * Get the names of the directories that matched at least one of the include + * patterns, an matched also at least one of the exclude patterns. + * The names are relative to the basedir. + * + * @return the names of the directories + */ + function getExcludedDirectories() { + $this->slowScan(); + return $this->dirsExcluded; + } + + /** + * Adds the array with default exclusions to the current exclusions set. + * + */ + function addDefaultExcludes() { + //$excludesLength = ($this->excludes == null) ? 0 : count($this->excludes); + foreach($this->DEFAULTEXCLUDES as $pattern) { + $pattern = str_replace('\\', DIRECTORY_SEPARATOR, $pattern); + $pattern = str_replace('/', DIRECTORY_SEPARATOR, $pattern); + $this->excludes[] = $pattern; + } + } + + /** + * Sets the selectors that will select the filelist. + * + * @param selectors specifies the selectors to be invoked on a scan + */ + public function setSelectors($selectors) { + $this->selectors = $selectors; + } + + /** + * Returns whether or not the scanner has included all the files or + * directories it has come across so far. + * + * @return true if all files and directories which have + * been found so far have been included. + */ + public function isEverythingIncluded() { + return $this->everythingIncluded; + } + + /** + * Tests whether a name should be selected. + * + * @param string $name The filename to check for selecting. + * @param string $file The full file path. + * @return boolean False when the selectors says that the file + * should not be selected, True otherwise. + */ + protected function isSelected($name, $file) { + if ($this->selectors !== null) { + for ($i=0,$size=count($this->selectors); $i < $size; $i++) { + if (($this->selectors[$i]->isSelected(new PhingFile($this->basedir), $name, new PhingFile($file))) === false) { + return false; + } + } + } + return true; + } + +} diff --git a/buildscripts/phing/classes/phing/util/ExtendedFileStream.php b/buildscripts/phing/classes/phing/util/ExtendedFileStream.php new file mode 100644 index 00000000..5fdcae47 --- /dev/null +++ b/buildscripts/phing/classes/phing/util/ExtendedFileStream.php @@ -0,0 +1,133 @@ +. + */ + + /** + * Extended file stream wrapper class which auto-creates directories + * + * @author Michiel Rook + * @version $Id: ExtendedFileStream.php,v 1.5 2005/12/27 15:51:26 hlellelid Exp $ + * @package phing.util + */ + class ExtendedFileStream + { + private $fp = NULL; + + static function registerStream() + { + if (!in_array("efile", stream_get_wrappers())) + { + stream_wrapper_register("efile", "ExtendedFileStream"); + } + } + + private function createDirectories($path) + { + $f = new PhingFile($path); + if (!$f->exists()) { + $f->mkdirs(); + } + } + + function stream_open($path, $mode, $options, &$opened_path) + { + /** Small fix for Windows */ + if ($path[8] == DIRECTORY_SEPARATOR) + { + $filepath = substr($path, 7); + } + else + { + $filepath = substr($path, 8); + } + + $this->createDirectories(dirname($filepath)); + + $this->fp = fopen($filepath, $mode); + + return true; + } + + function stream_close() + { + fclose($this->fp); + $this->fp = NULL; + } + + function stream_read($count) + { + return fread($this->fp, $count); + } + + function stream_write($data) + { + return fwrite($this->fp, $data); + } + + function stream_eof() + { + return feof($this->fp); + } + + function stream_tell() + { + return ftell($this->fp); + } + + function stream_seek($offset, $whence) + { + return fseek($this->fp, $offset, $whence); + } + + function stream_flush() + { + return fflush($this->fp); + } + + function stream_stat() + { + return fstat($this->fp); + } + + function unlink($path) + { + return FALSE; + } + + function rename($path_from, $path_to) + { + return FALSE; + } + + function mkdir($path, $mode, $options) + { + return FALSE; + } + + function rmdir($path, $options) + { + return FALSE; + } + }; + +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/util/FileUtils.php b/buildscripts/phing/classes/phing/util/FileUtils.php new file mode 100644 index 00000000..0f5ff19a --- /dev/null +++ b/buildscripts/phing/classes/phing/util/FileUtils.php @@ -0,0 +1,294 @@ +. + */ + +include_once 'phing/system/lang/Character.php'; +include_once 'phing/util/StringHelper.php'; +include_once 'phing/system/io/BufferedReader.php'; +include_once 'phing/system/io/BufferedWriter.php'; +include_once 'phing/filters/util/ChainReaderHelper.php'; +include_once 'phing/system/io/PhingFile.php'; + +/** + * File utility class. + * - handles os independent stuff etc + * - mapper stuff + * - filter stuff + * + * @package phing.util + * @version $Revision: 1.10 $ + */ +class FileUtils { + + /** + * Returns a new Reader with filterchains applied. If filterchains are empty, + * simply returns passed reader. + * + * @param Reader $in Reader to modify (if appropriate). + * @param array &$filterChains filter chains to apply. + * @param Project $project + * @return Reader Assembled Reader (w/ filter chains). + */ + function getChainedReader(Reader $in, &$filterChains, Project $project) { + if (!empty($filterChains)) { + $crh = new ChainReaderHelper(); + $crh->setBufferSize(65536); // 64k buffer, but isn't being used (yet?) + $crh->setPrimaryReader($in); + $crh->setFilterChains($filterChains); + $crh->setProject($project); + $rdr = $crh->getAssembledReader(); + return $rdr; + } else { + return $in; + } + } + + /** + * Copies a file using filter chains. + * + * @param PhingFile $sourceFile + * @param PhingFile $destFile + * @param boolean $overwrite + * @param boolean $preserveLastModified + * @param array $filterChains + * @param Project $project + * @return void + */ + function copyFile(PhingFile $sourceFile, PhingFile $destFile, $overwrite = false, $preserveLastModified = true, &$filterChains = null, Project $project) { + + if ($overwrite || !$destFile->exists() || $destFile->lastModified() < $sourceFile->lastModified()) { + if ($destFile->exists() && $destFile->isFile()) { + $destFile->delete(); + } + + // ensure that parent dir of dest file exists! + $parent = $destFile->getParentFile(); + if ($parent !== null && !$parent->exists()) { + $parent->mkdirs(); + } + + if ((is_array($filterChains)) && (!empty($filterChains))) { + + $in = self::getChainedReader(new BufferedReader(new FileReader($sourceFile)), $filterChains, $project); + $out = new BufferedWriter(new FileWriter($destFile)); + + // New read() methods returns a big buffer. + while(-1 !== ($buffer = $in->read())) { // -1 indicates EOF + $out->write($buffer); + } + + if ( $in !== null ) + $in->close(); + if ( $out !== null ) + $out->close(); + } else { + // simple copy (no filtering) + $sourceFile->copyTo($destFile); + } + + if ($preserveLastModified) { + $destFile->setLastModified($sourceFile->lastModified()); + } + + } + } + + /** + * Interpret the filename as a file relative to the given file - + * unless the filename already represents an absolute filename. + * + * @param $file the "reference" file for relative paths. This + * instance must be an absolute file and must not contain + * ./ or ../ sequences (same for \ instead of /). + * @param $filename a file name + * + * @return PhingFile A PhingFile object pointing to an absolute file that doesn't contain ./ or ../ sequences + * and uses the correct separator for the current platform. + */ + function resolveFile($file, $filename) { + // remove this and use the static class constant File::seperator + // as soon as ZE2 is ready + $fs = FileSystem::getFileSystem(); + + $filename = str_replace('/', $fs->getSeparator(), str_replace('\\', $fs->getSeparator(), $filename)); + + // deal with absolute files + if (StringHelper::startsWith($fs->getSeparator(), $filename) || + (strlen($filename) >= 2 && Character::isLetter($filename{0}) && $filename{1} === ':')) { + return new PhingFile($this->normalize($filename)); + } + + if (strlen($filename) >= 2 && Character::isLetter($filename{0}) && $filename{1} === ':') { + return new PhingFile($this->normalize($filename)); + } + + $helpFile = new PhingFile($file->getAbsolutePath()); + + $tok = strtok($filename, $fs->getSeparator()); + while ($tok !== false) { + $part = $tok; + if ($part === '..') { + $parentFile = $helpFile->getParent(); + if ($parentFile === null) { + $msg = "The file or path you specified ($filename) is invalid relative to ".$file->getPath(); + throw new IOException($msg); + } + $helpFile = new PhingFile($parentFile); + } else if ($part === '.') { + // Do nothing here + } else { + $helpFile = new PhingFile($helpFile, $part); + } + $tok = strtok($fs->getSeparator()); + } + return new PhingFile($helpFile->getAbsolutePath()); + } + + /** + * Normalize the given absolute path. + * + * This includes: + * - Uppercase the drive letter if there is one. + * - Remove redundant slashes after the drive spec. + * - resolve all ./, .\, ../ and ..\ sequences. + * - DOS style paths that start with a drive letter will have + * \ as the separator. + * @param string $path Path to normalize. + * @return string + */ + function normalize($path) { + + $path = (string) $path; + $orig = $path; + + $path = str_replace('/', DIRECTORY_SEPARATOR, str_replace('\\', DIRECTORY_SEPARATOR, $path)); + + // make sure we are dealing with an absolute path + if (!StringHelper::startsWith(DIRECTORY_SEPARATOR, $path) + && !(strlen($path) >= 2 && Character::isLetter($path{0}) && $path{1} === ':')) { + throw new IOException("$path is not an absolute path"); + } + + $dosWithDrive = false; + $root = null; + + // Eliminate consecutive slashes after the drive spec + + if (strlen($path) >= 2 && Character::isLetter($path{0}) && $path{1} === ':') { + $dosWithDrive = true; + + $ca = str_replace('/', '\\', $path); + $ca = StringHelper::toCharArray($ca); + + $path = strtoupper($ca[0]).':'; + + for ($i=2, $_i=count($ca); $i < $_i; $i++) { + if (($ca[$i] !== '\\') || + ($ca[$i] === '\\' && $ca[$i - 1] !== '\\') + ) { + $path .= $ca[$i]; + } + } + + $path = str_replace('\\', DIRECTORY_SEPARATOR, $path); + + if (strlen($path) == 2) { + $root = $path; + $path = ""; + } else { + $root = substr($path, 0, 3); + $path = substr($path, 3); + } + + } else { + if (strlen($path) == 1) { + $root = DIRECTORY_SEPARATOR; + $path = ""; + } else if ($path{1} == DIRECTORY_SEPARATOR) { + // UNC drive + $root = DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR; + $path = substr($path, 2); + } + else { + $root = DIRECTORY_SEPARATOR; + $path = substr($path, 1); + } + } + + $s = array(); + array_push($s, $root); + $tok = strtok($path, DIRECTORY_SEPARATOR); + while ($tok !== false) { + $thisToken = $tok; + if ("." === $thisToken) { + $tok = strtok(DIRECTORY_SEPARATOR); + continue; + } elseif (".." === $thisToken) { + if (count($s) < 2) { + // using '..' in path that is too short + throw new IOException("Cannot resolve path: $orig"); + } else { + array_pop($s); + } + } else { // plain component + array_push($s, $thisToken); + } + $tok = strtok(DIRECTORY_SEPARATOR); + } + + $sb = ""; + for ($i=0,$_i=count($s); $i < $_i; $i++) { + if ($i > 1) { + // not before the filesystem root and not after it, since root + // already contains one + $sb .= DIRECTORY_SEPARATOR; + } + $sb .= (string) $s[$i]; + } + + + $path = (string) $sb; + if ($dosWithDrive === true) { + $path = str_replace('/', '\\', $path); + } + return $path; + } + + /** + * @return boolean Whether contents of two files is the same. + */ + public function contentEquals(PhingFile $file1, PhingFile $file2) { + + if (!($file1->exists() || $file2->exists())) { + return false; + } + + if (!($file1->canRead() || $file2->canRead())) { + return false; + } + + $c1 = file_get_contents($file1->getAbsolutePath()); + $c2 = file_get_contents($file2->getAbsolutePath()); + + return trim($c1) == trim($c2); + } + +} +?> diff --git a/buildscripts/phing/classes/phing/util/LogWriter.php b/buildscripts/phing/classes/phing/util/LogWriter.php new file mode 100644 index 00000000..9e704fc3 --- /dev/null +++ b/buildscripts/phing/classes/phing/util/LogWriter.php @@ -0,0 +1,96 @@ +. + */ + + require_once 'phing/system/io/Writer.php'; + require_once 'phing/Task.php'; + + /** + * Extends the Writer class to output messages to Phing's log + * + * @author Michiel Rook + * @version $Id: LogWriter.php,v 1.2 2004/11/09 13:16:11 hlellelid Exp $ + * @package phing.util + */ + class LogWriter extends Writer + { + private $task = NULL; + + private $level = NULL; + + /** + * Constructs a new LogWriter object + */ + function __construct(Task $task, $level = PROJECT_MSG_INFO) + { + $this->task = $task; + $this->level = $level; + } + + /** + * @see Writer::write() + */ + function write($buf, $off = null, $len = null) + { + $lines = explode("\n", $buf); + + foreach ($lines as $line) + { + if ($line == "") + { + continue; + } + + $this->task->log($line, $this->level); + } + } + + /** + * @see Writer::reset() + */ + function reset() + { + } + + /** + * @see Writer::close() + */ + function close() + { + } + + /** + * @see Writer::open() + */ + function open() + { + } + + /** + * @see Writer::getResource() + */ + function getResource() + { + return $this->task; + } + } + +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/util/PathTokenizer.php b/buildscripts/phing/classes/phing/util/PathTokenizer.php new file mode 100644 index 00000000..29c0f059 --- /dev/null +++ b/buildscripts/phing/classes/phing/util/PathTokenizer.php @@ -0,0 +1,245 @@ +. + */ + + + +include_once 'phing/util/StringHelper.php'; + + + +/** + + * A Path tokenizer takes a path and returns the components that make up + + * that path. + + * + + * The path can use path separators of either ':' or ';' and file separators + + * of either '/' or '\'. + + * + + * @author Hans Lellelid (Phing) + + * @author Conor MacNeill (Ant) + + * @author Jeff Tulley (Ant) + + * @pacakge phing.util + + */ + +class PathTokenizer { + + + + /** + + * A array of tokens, created by preg_split(). + + */ + + private $tokens = array(); + + + + /** + + * A string which stores any path components which have been read ahead + + * due to DOS filesystem compensation. + + * @var string + + */ + + private $lookahead; + + + + /** + + * Flag to indicate whether or not we are running on a platform with a + + * DOS style filesystem + + * @var boolean + + */ + + private $dosStyleFilesystem; + + + + /** + + * Constructs a path tokenizer for the specified path. + + * + + * @param path The path to tokenize. Must not be null. + + */ + + public function __construct($path) { + + // on Windows and Unix, we can ignore delimiters and still have + + // enough information to tokenize correctly. + + $this->tokens = preg_split("/[;:]/", $path, -1, PREG_SPLIT_NO_EMPTY); + + $this->dosStyleFilesystem = ( PATH_SEPARATOR == ';'); + + } + + + + /** + + * Tests if there are more path elements available from this tokenizer's + + * path. If this method returns true, then a subsequent call + + * to nextToken will successfully return a token. + + * + + * @return true if and only if there is at least one token + + * in the string after the current position; false otherwise. + + */ + + public function hasMoreTokens() { + + if ($this->lookahead !== null) { + + return true; + + } + + return !empty($this->tokens); + + } + + + + /** + + * Returns the next path element from this tokenizer. + + * + + * @return the next path element from this tokenizer. + + * + + * @throws Exception if there are no more elements in this tokenizer's path. + + */ + + public function nextToken() { + + + + if ($this->lookahead !== null) { + + $token = $this->lookahead; + + $this->lookahead = null; + + } else { + + $token = trim(array_shift($this->tokens)); + + } + + + + + + if (strlen($token) === 1 && Character::isLetter($token{0}) + + && $this->dosStyleFilesystem + + && !empty($this->tokens)) { + + // we are on a dos style system so this path could be a drive + + // spec. We look at the next token + + $nextToken = trim(array_shift($this->tokens)); + + if (StringHelper::startsWith('\\', $nextToken) || StringHelper::startsWith('/', $nextToken)) { + + // we know we are on a DOS style platform and the next path + + // starts with a slash or backslash, so we know this is a + + // drive spec + + $token .= ':' . $nextToken; + + } else { + + // store the token just read for next time + + $this->lookahead = $nextToken; + + } + + } + + + + return $token; + + } + + + + /** + + * Non StringTokenizer function, that indicates whether the specified path is contained in loaded tokens. + + * We can do this easily because in PHP implimentation we're using arrays. + + * @param string $path path to search for. + + * @return boolean + + */ + + public function contains($path) { + + return in_array($path, $this->tokens, true); + + } + + + +} + + + diff --git a/buildscripts/phing/classes/phing/util/SourceFileScanner.php b/buildscripts/phing/classes/phing/util/SourceFileScanner.php new file mode 100644 index 00000000..b157dcb9 --- /dev/null +++ b/buildscripts/phing/classes/phing/util/SourceFileScanner.php @@ -0,0 +1,159 @@ +. + */ + +/** + * Utility class that collects the functionality of the various + * scanDir methods that have been scattered in several tasks before. + * + * The only method returns an array of source files. The array is a + * subset of the files given as a parameter and holds only those that + * are newer than their corresponding target files. + * @package phing.util + */ +class SourceFileScanner { + + /** Instance of FileUtils */ + private $fileUtils; + + /** Task this class is working for -- for logging purposes. */ + private $task; + + /** + * @param task The task we should log messages through + */ + function __construct($task) { + $this->task = $task; + $this->fileUtils = new FileUtils(); + } + + /** + * Restrict the given set of files to those that are newer than + * their corresponding target files. + * + * @param files the original set of files + * @param srcDir all files are relative to this directory + * @param destDir target files live here. if null file names + * returned by the mapper are assumed to be absolute. + * @param FilenameMapper knows how to construct a target file names from + * source file names. + * @param force Boolean that determines if the files should be + * forced to be copied. + */ + function restrict(&$files, $srcDir, $destDir, $mapper, $force = false) { + $now = time(); + $targetList = ""; + + /* + If we're on Windows, we have to munge the time up to 2 secs to + be able to check file modification times. + (Windows has a max resolution of two secs for modification times) + */ + $osname = strtolower(Phing::getProperty('os.name')); + + // indexOf() + $index = ((($res = strpos($osname, 'win')) === false) ? -1 : $res); + if ($index >= 0 ) { + $now += 2000; + } + + $v = array(); + + for ($i=0, $size=count($files); $i < $size; $i++) { + + $targets = $mapper->main($files[$i]); + if (empty($targets)) { + $this->task->log($files[$i]." skipped - don't know how to handle it", PROJECT_MSG_VERBOSE); + continue; + } + + $src = null; + try { + if ($srcDir === null) { + $src = new PhingFile($files[$i]); + } else { + $src = $this->fileUtils->resolveFile($srcDir, $files[$i]); + } + + if ($src->lastModified() > $now) { + $this->task->log("Warning: ".$files[$i]." modified in the future (".$src->lastModified()." > ".$now.")", PROJECT_MSG_WARN); + } + } catch (IOException $ioe) { + $this->task->log("Unable to read file ".$files[$i]." (skipping): " . $ioe->getMessage()); + continue; + } + + $added = false; + $targetList = ""; + + for ($j=0,$_j=count($targets); (!$added && $j < $_j); $j++) { + + $dest = null; + if ($destDir === null) { + $dest = new PhingFile($targets[$j]); + } else { + $dest = $this->fileUtils->resolveFile($destDir, $targets[$j]); + } + + if (!$dest->exists()) { + $this->task->log($files[$i]." added as " . $dest->__toString() . " doesn't exist.", PROJECT_MSG_VERBOSE); + $v[] =$files[$i]; + $added = true; + } elseif ($src->lastModified() > $dest->lastModified()) { + $this->task->log($files[$i]." added as " . $dest->__toString() . " is outdated.", PROJECT_MSG_VERBOSE ); + $v[]=$files[$i]; + $added = true; + } elseif ($force === true) { + $this->task->log($files[$i]." added as " . $dest->__toString() . " is forced to be overwritten.", PROJECT_MSG_VERBOSE ); + $v[]=$files[$i]; + $added = true; + } else { + if (strlen($targetList) > 0) { + $targetList .= ", "; + } + $targetList .= $dest->getAbsolutePath(); + } + } + + if (!$added) { + $this->task->log($files[$i]." omitted as ".$targetList." ".(count($targets) === 1 ? " is " : " are ")."up to date.", PROJECT_MSG_VERBOSE); + } + + } + $result = array(); + $result = $v; + return $result; + } + + /** + * Convenience layer on top of restrict that returns the source + * files as PhingFile objects (containing absolute paths if srcDir is + * absolute). + */ + function restrictAsFiles(&$files, &$srcDir, &$destDir, &$mapper) { + $res = $this->restrict($files, $srcDir, $destDir, $mapper); + $result = array(); + for ($i=0; $i diff --git a/buildscripts/phing/classes/phing/util/StringHelper.php b/buildscripts/phing/classes/phing/util/StringHelper.php new file mode 100644 index 00000000..5d4bfd7a --- /dev/null +++ b/buildscripts/phing/classes/phing/util/StringHelper.php @@ -0,0 +1,209 @@ + + * @package phing.system.util + */ +class StringHelper { + + private static $TRUE_VALUES = array("on", "true", "t", "yes"); + private static $FALSE_VALUES = array("off", "false", "f", "no"); + + /** + * Replaces identifier tokens with corresponding text values in passed string. + * + * @params array $strings Array of strings to multiply. (If string is passed, will convert to array) + * @params array $tokens The tokens to search for. + * @params array $replacements The values with which to replace found tokens. + * @return string + */ + public static function multiply($strings, $tokens, $replacements) { + $strings = (array) $strings; + $results = array(); + foreach ($strings as $string) { + $results[] = str_replace($tokens, $replacements, $string); + } + return $results; + } + + /** + * Remove qualification to name. + * E.g. eg.Cat -> Cat + * @param string $qualifiedName + * @param string $separator Character used to separate. + */ + public static function unqualify($qualifiedName, $separator = '.') { + // if false, then will be 0 + $pos = strrpos($qualifiedName, $separator); + if ($pos === false) { + return $qualifiedName; // there is no '.' in the qualifed name + } else { + return substr($qualifiedName, $pos + 1); // start just after '.' + } + } + + /** + * Converts a string to an indexed array of chars + * There's really no reason for this to be used in PHP, since strings + * are all accessible using the $string{0} notation. + * @param string $string + * @return array + * @deprecated + */ + public static function toCharArray($str) { + $ret=array(); + $len=strlen($str); + for ($i=0; $i < $len; $i++) { + $ret[] = $str{$i}; + } + return $ret; + } + + /** + * Get the qualifier part of a qualified name. + * E.g. eg.Cat -> eg + * @return string + */ + public static function qualifier($qualifiedName, $seperator = '.') { + $pos = strrchr($qualifiedName, $seperator); + if ($pos === false) { + return ''; + } else { + return substr($qualifiedName, 0, $pos); + } + } + + /** + * @param array $columns String[] + * @param string $prefix + * @return array String[] + */ + public static function prefix( $columns, $prefix) { + if ($prefix == null) return $columns; + $qualified = array(); + foreach($columns as $key => $column) { + $qualified[$key] = $prefix . $column; + } + return $qualified; + } + + /** + * + * @return string + */ + public static function root($qualifiedName, $separator = '.') { + $loc = strpos($qualifiedName, $separator); + return ($loc === false) ? $qualifiedName : substr($qualifiedName, 0, $loc); + } + + /** + * @return int + */ + public static function hashCode($string) { + return crc32($string); + } + + /** + * @return boolean + */ + public static function booleanValue($s) { + if (is_bool($s)) { + return $s; // it's already boolean (not a string) + } + // otherwise assume it's something like "true" or "t" + $trimmed = strtolower(trim($s)); + return (boolean) in_array($trimmed, self::$TRUE_VALUES); + } + + /** tests if a string is a representative of a boolean */ + public static function isBoolean($s) { + + if (is_bool($s)) { + return true; // it already is boolean + } + + if ($s === "" || $s === null || !is_string($s)) { + return false; // not a valid string for testing + } + + $test = trim(strtolower($s)); + return (boolean) in_array($test, array_merge(self::$FALSE_VALUES, self::$TRUE_VALUES)); + } + + /** + * Creates a key based on any number of passed params. + * @return string + */ + public static function key() { + $args = func_get_args(); + return serialize($args); + } + + /** tests if a string starts with a given string */ + public static function startsWith($check, $string) { + if ($check === "" || $check === $string) { + return true; + } else { + return (strpos($string, $check) === 0) ? true : false; + } + } + + /** tests if a string ends with a given string */ + public static function endsWith($check, $string) { + if ($check === "" || $check === $string) { + return true; + } else { + return (strpos(strrev($string), strrev($check)) === 0) ? true : false; + } + } + + /** + * a natural way of getting a subtring, php's circular string buffer and strange + * return values suck if you want to program strict as of C or friends + */ + public static function substring($string, $startpos, $endpos = -1) { + $len = strlen($string); + $endpos = (int) (($endpos === -1) ? $len-1 : $endpos); + if ($startpos > $len-1 || $startpos < 0) { + trigger_error("substring(), Startindex out of bounds must be 0 $len-1 || $endpos < $startpos) { + trigger_error("substring(), Endindex out of bounds must be $startpos \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/util/regexp/PregEngine.php b/buildscripts/phing/classes/phing/util/regexp/PregEngine.php new file mode 100644 index 00000000..758b40f3 --- /dev/null +++ b/buildscripts/phing/classes/phing/util/regexp/PregEngine.php @@ -0,0 +1,105 @@ +. + */ + +require_once 'phing/util/regexp/RegexpEngine.php'; + +/** + * PREG Regexp Engine. + * Implements a regexp engine using PHP's preg_match(), preg_match_all(), and preg_replace() functions. + * + * @author hans lellelid, hans@velum.net + * @package phing.util.regex + */ +class PregEngine implements RegexpEngine { + + /** + * @var boolean + */ + private $ignoreCase = false; + + /** + * Sets whether or not regex operation is case sensitive. + * @param boolean $bit + * @return void + */ + function setIgnoreCase($bit) { + $this->ignoreCase = (boolean) $bit; + } + + /** + * Gets whether or not regex operation is case sensitive. + * @return boolean + */ + function getIgnoreCase() { + return $this->ignoreCase; + } + + /** + * The pattern needs to be converted into PREG style -- which includes adding expression delims & any flags, etc. + * @param string $pattern + * @return string prepared pattern. + */ + private function preparePattern($pattern) + { + return '/'.$pattern.'/'.($this->ignoreCase ? 'i' : ''); + } + + /** + * Matches pattern against source string and sets the matches array. + * @param string $pattern The regex pattern to match. + * @param string $source The source string. + * @param array $matches The array in which to store matches. + * @return boolean Success of matching operation. + */ + function match($pattern, $source, &$matches) { + return preg_match($this->preparePattern($pattern), $source, $matches); + } + + /** + * Matches all patterns in source string and sets the matches array. + * @param string $pattern The regex pattern to match. + * @param string $source The source string. + * @param array $matches The array in which to store matches. + * @return boolean Success of matching operation. + */ + function matchAll($pattern, $source, &$matches) { + return preg_match_all($this->preparePattern($pattern), $source, $matches); + } + + /** + * Replaces $pattern with $replace in $source string. + * References to \1 group matches will be replaced with more preg-friendly + * $1. + * @param string $pattern The regex pattern to match. + * @param string $replace The string with which to replace matches. + * @param string $source The source string. + * @return string The replaced source string. + */ + function replace($pattern, $replace, $source) { + // convert \1 -> $1, because we want to use the more generic \1 in the XML + // but PREG prefers $1 syntax. + $replace = preg_replace('/[^\\\]\\\(\d+)/', '$1', $replace); + return preg_replace($this->preparePattern($pattern), $replace, $source); + } + +} + +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/util/regexp/Regexp.php b/buildscripts/phing/classes/phing/util/regexp/Regexp.php new file mode 100644 index 00000000..68c06668 --- /dev/null +++ b/buildscripts/phing/classes/phing/util/regexp/Regexp.php @@ -0,0 +1,168 @@ +. + */ + +/** + * A factory class for regex functions. + * @author Hans Lellelid + * @package phing.util.regexp + * @version $Revision: 1.5 $ + */ +class Regexp { + + /** + * Matching groups found. + * @var array + */ + private $groups = array(); + + /** + * Pattern to match. + * @var string + */ + private $pattern; + + /** + * Replacement pattern. + * @var string + */ + private $replace; + + /** + * The regex engine -- e.g. 'preg' or 'ereg'; + * @var RegexpEngine + */ + private $engine; + + /** + * Constructor sets the regex engine to use (preg by default). + * @param string $_engineType The regex engine to use. + */ + function __construct($engineType='preg') { + if ($engineType == 'preg') { + include_once 'phing/util/regexp/PregEngine.php'; + $this->engine = new PregEngine(); + } elseif ($engineType == 'ereg') { + include_once 'phing/util/regexp/EregEngine.php'; + $this->engine = new EregEngine(); + } else { + throw new BuildException("Invalid engine type for Regexp: " . $engineType); + } + } + + /** + * Sets pattern to use for matching. + * @param string $pat The pattern to match on. + * @return void + */ + public function setPattern($pat) { + $this->pattern = (string) $pat; + } + + + /** + * Gets pattern to use for matching. + * @return string The pattern to match on. + */ + public function getPattern() { + return $this->pattern; + } + + /** + * Sets replacement string. + * @param string $rep The pattern to replace matches with. + * @return void + */ + public function setReplace($rep) { + $this->replace = (string) $rep; + } + + /** + * Gets replacement string. + * @return string The pattern to replace matches with. + * @return void + */ + public function getReplace() { + return $this->replace; + } + + /** + * Performs match of specified pattern against $subject. + * @param string $subject The subject, on which to perform matches. + * @return boolean Whether or not pattern matches subject string passed. + */ + public function matches($subject) { + if($this->pattern === null) { + throw new Exception("No pattern specified for regexp match()."); + } + return $this->engine->match($this->pattern, $subject, $this->groups); + } + + /** + * Performs replacement of specified pattern and replacement strings. + * @param string $subject Text on which to perform replacement. + * @return string subject after replacement has been performed. + */ + public function replace($subject) { + if ($this->pattern === null || $this->replace === null) { + throw new Exception("Missing pattern or replacement string regexp replace()."); + } + return $this->engine->replace($this->pattern, $this->replace, $subject); + } + + /** + * Get array of matched groups. + * @return array Matched groups + */ + function getGroups() { + return $this->groups; + } + + /** + * Get specific matched group. + * @param integer $idx + * @return string specified group or NULL if group is not set. + */ + function getGroup($idx) { + if (!isset($this->groups[$idx])) { + return null; + } + return $this->groups[$idx]; + } + + /** + * Sets whether the regexp matching is case insensitive. + * (default is false -- i.e. case sensisitive) + * @param boolean $bit + */ + function setIgnoreCase($bit) { + $this->engine->setIgnoreCase($bit); + } + + /** + * Gets whether the regexp matching is case insensitive. + * @return boolean + */ + function getIgnoreCase() { + return $this->engine->getIgnoreCase(); + } +} + +?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/util/regexp/RegexpEngine.php b/buildscripts/phing/classes/phing/util/regexp/RegexpEngine.php new file mode 100644 index 00000000..7d323466 --- /dev/null +++ b/buildscripts/phing/classes/phing/util/regexp/RegexpEngine.php @@ -0,0 +1,74 @@ +. + */ + +/** + * Contains some shared attributes and methods -- and some abstract methods with + * engine-specific implementations that sub-classes must override. + * + * @author Hans Lellelid + * @package phing.util.regex + * @version $Revision: 1.4 $ + */ +interface RegexpEngine { + + /** + * Sets whether or not regex operation should ingore case. + * @param boolean $bit + * @return void + */ + public function setIgnoreCase($bit); + + /** + * Returns status of ignore case flag. + * @return boolean + */ + public function getIgnoreCase(); + + /** + * Matches pattern against source string and sets the matches array. + * @param string $pattern The regex pattern to match. + * @param string $source The source string. + * @param array $matches The array in which to store matches. + * @return boolean Success of matching operation. + */ + function match($pattern, $source, &$matches); + + /** + * Matches all patterns in source string and sets the matches array. + * @param string $pattern The regex pattern to match. + * @param string $source The source string. + * @param array $matches The array in which to store matches. + * @return boolean Success of matching operation. + */ + function matchAll($pattern, $source, &$matches); + + /** + * Replaces $pattern with $replace in $source string. + * @param string $pattern The regex pattern to match. + * @param string $replace The string with which to replace matches. + * @param string $source The source string. + * @return string The replaced source string. + */ + function replace($pattern, $replace, $source); + +} + +?> \ No newline at end of file diff --git a/buildscripts/phing/etc/VERSION.TXT b/buildscripts/phing/etc/VERSION.TXT new file mode 100644 index 00000000..00fa3b83 --- /dev/null +++ b/buildscripts/phing/etc/VERSION.TXT @@ -0,0 +1 @@ +Phing 2.2 BRANCH (SVN) \ No newline at end of file diff --git a/buildscripts/phing/etc/coverage-frames.xsl b/buildscripts/phing/etc/coverage-frames.xsl new file mode 100644 index 00000000..5e8d8e3e --- /dev/null +++ b/buildscripts/phing/etc/coverage-frames.xsl @@ -0,0 +1,669 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Coverage Results. + + + + + + + + + <h2>Frame Alert</h2> + <p> + This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. + </p> + + + + + + + + .bannercell { + border: 0px; + padding: 0px; + } + body { + margin-left: 10; + margin-right: 10; + background-color:#FFFFFF; + font-family: verdana,arial,sanserif; + color:#000000; + } + a { + color: #003399; + } + a:hover { + color: #888888; + } + .a td { + background: #efefef; + } + .b td { + background: #fff; + } + th, td { + text-align: left; + vertical-align: top; + } + th { + font-weight:bold; + background: #ccc; + color: black; + } + table, th, td { + font-size: 12px; + border: none + } + table.log tr td, tr th { + } + h2 { + font-weight:bold; + font-size: 12px; + margin-bottom: 5; + } + h3 { + font-size:100%; + font-weight: 12px; + background: #DFDFDF + color: white; + text-decoration: none; + padding: 5px; + margin-right: 2px; + margin-left: 2px; + margin-bottom: 0; + } + .small { + font-size: 9px; + } +TD.empty { + FONT-SIZE: 2px; BACKGROUND: #c0c0c0; BORDER:#9c9c9c 1px solid; + color: #c0c0c0; +} +TD.fullcover { + FONT-SIZE: 2px; BACKGROUND: #00df00; BORDER:#9c9c9c 1px solid; + color: #00df00; +} +TD.covered { + FONT-SIZE: 2px; BACKGROUND: #00df00; BORDER-LEFT:#9c9c9c 1px solid;BORDER-TOP:#9c9c9c 1px solid;BORDER-BOTTOM:#9c9c9c 1px solid; + color: #00df00; +} +TD.uncovered { + FONT-SIZE: 2px; BACKGROUND: #df0000; BORDER:#9c9c9c 1px solid; + color: #df0000; +} +PRE.srcLine { + BACKGROUND: #ffffff; MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px; +} +td.lineCount, td.coverageCount { + BACKGROUND: #F0F0F0; PADDING-RIGHT: 3px; + text-align: right; +} +td.lineCountHighlight { + background: #C8C8F0; PADDING-RIGHT: 3px; + text-align: right; +} +td.coverageCountHighlight { + background: #F0C8C8; PADDING-RIGHT: 3px; + text-align: right; +} +span.srcLineHighlight { + background: #F0C8C8; +} +span.srcLine { + background: #C8C8F0; +} +TD.srcLineClassStart { + WIDTH: 100%; BORDER-TOP:#dcdcdc 1px solid; FONT-WEIGHT: bold; +} +.srcLine , .srcLine ol, .srcLine ol li {margin: 0;} +.srcLine .de1, .srcLine .de2 {font-family: 'Courier New', Courier, monospace; font-weight: normal;} +.srcLine .imp {font-weight: bold; color: red;} +.srcLine .kw1 {color: #b1b100;} +.srcLine .kw2 {color: #000000; font-weight: bold;} +.srcLine .kw3 {color: #000066;} +.srcLine .co1 {color: #808080; font-style: italic;} +.srcLine .co2 {color: #808080; font-style: italic;} +.srcLine .coMULTI {color: #808080; font-style: italic;} +.srcLine .es0 {color: #000099; font-weight: bold;} +.srcLine .br0 {color: #66cc66;} +.srcLine .st0 {color: #ff0000;} +.srcLine .nu0 {color: #cc66cc;} +.srcLine .me1 {color: #006600;} +.srcLine .me2 {color: #006600;} +.srcLine .re0 {color: #0000ff;} + + + + + + + + + +

        All Classes

        + + + + + + + / + .html + + + + + +
        + + + + (-) + + + () + + +
        + + +
        + + + + + + + + +

        Overview

        +

        All Packages

        + + + + + + + +
        + + + +
        + + +
        + + + + + + + + + + + + + + + + + +
        Packages: Classes: Methods: LOC: Statements:
        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        StatementsMethodsTotal coverage
        Project

        PackagesStatementsMethodsTotal coverage
        + + + +
        + + + + + + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        +

        +
        + +

        Classes

        + + + + + + + +
        + + + + (-) + + + () + + +
        + + +
        + + + + + + + + + + + + + + + + + + + +
        Classes: Methods: LOC: Statements:
        +
        + + + + + + + + + + + + + + + + + + + + + + + + +
        PackageStatementsMethodsTotal coverage

        ClassesStatementsMethodsTotal coverage
        + + + +
        + + + + + + + + + + + + + + + + + + +
        Methods: LOC: Statements:
        +
        + + + + + + + + + + + + + + +
        Source fileStatementsMethodsTotal coverage
        + + +
        +
        + + + + +
        + + + + + + + + + + + + +
        + + http://phing.info/ + +

        Source Code Coverage

        Designed for use with PHPUnit2, Xdebug and Phing.
        +
        +
        + + + + + + +

        Report generated at
        +
        + + +
        - + + - + + - + + + + +
         
        +
        + + + + + + + + + + + + + + + + + + + + +
           
        +
        0 + + srcLineClassStart + + + +
        +
        +
        + + +
        +
        +
        + +
        +
        +
        + + + + +
        + + http://phing.info/ + + + Phing +
        + + + +

        + + + + + + + +

        +
        + Phing +
        +
        + + + + + + + + + failed + complete + + + + + + + + + + + + + +
        Build FailedBuild CompleteTotal Time:
        + +
        + See the stacktrace. +
        +
        + + + +
        phing.file
        phing.version
        + +

        Build events

        + + + + + + + +
        targettaskmessage
        +

        + + + +

        Error details

        + + +
        +
        +
        + +

        +
        + + + +
        [ ] + +
        + + +
        + +

        Tests

        + + + + + + + + + +
        + + + + + + + + + + + + Unit Test Classes: <xsl:value-of select="$name"/> + + + + + + + + + +
        +

        + + <none> +

        +
        + +

        Classes

        + + + + + + + +
        + +
        + + +
        + + + + + + + All Unit Test Classes + + + + + +

        Classes

        + + + + +
        + + +
        + + + + + + + + + / + .html + + + + + + + + + + + + + All Unit Test Packages + + + + + +

        Home

        +

        Packages

        + + + + +
        + + +
        + + + + + + + <none> + + + + + + + + + + Unit Test Results: Summary + + + + + + open('allclasses-frame.html','classListFrame') + +

        Summary

        + + + + + + + + + + + + + + + + + Error + Failure + Pass + + + + + + + + + +
        TestsFailuresErrorsSuccess rateTime
        + + + + + + + +
        + + + + +
        + Note: failures are anticipated and checked for with assertions while errors are unanticipated. +
        + +

        Packages

        + + + + + + + + + + + Error + Failure + Pass + + + + + + + + + +
        + + <none> + + + + +
        + + + +
        + + + + + + + + + + + + open('package-frame.html','classListFrame') + +

        Package

        + + + + + +

        Classes

        +

        + + + + + +
        +

        +
        + + + +
        + + + + + + + ../ + + + + + + ../ + + + + + + + + stylesheet.css + + + + + +

        Unit Test Results

        + + + + + +
        Designed for use with PHPUnit2 and Phing.
        +
        +
        + + + + + + +

        Report generated at
        +
        + + + + + Name + Tests + Errors + Failures + Time(s) + + + + + + + Name + Status + Type + Time(s) + + + + + + + + + + Error + Failure + Pass + + + + + + + + + + + + + + + + + + Error + Failure + TableRowColor + + + + + + Failure + + + + Error + + + + Success + + + + + + + + + + + + + + + + + + + + + + + + + N/A + + + + + +

        + + + + + +
        + + + + + + +
        + + + +
        + + + +
        +
        + + + + + + + + + + + + diff --git a/buildscripts/phing/etc/phpunit2-noframes.xsl b/buildscripts/phing/etc/phpunit2-noframes.xsl new file mode 100644 index 00000000..d2c772da --- /dev/null +++ b/buildscripts/phing/etc/phpunit2-noframes.xsl @@ -0,0 +1,436 @@ + + + + + + + + + + + Unit Test Results + + + + + + + + +
        + + + +
        + + + +
        + + + + + + + +
        + + + + + + + + +

        Packages

        + Note: package statistics are not computed recursively, they only sum up all of its testsuites numbers. + + + + + + + + + + + + + + + + + Failure + Error + + + + + + + + + +
        + + + +
        +
        + + + + + + + + + + + + +

        Package

        + + + + + + +
        + Back to top +

        +

        + + + + + + + + +

        TestCase

        + + + + + + + + + + +
        +

        + + Back to top + + + + +

        Summary

        + + + + + + + + + + + + + + + + + Failure + Error + + + + + + + + + +
        TestsFailuresErrorsSuccess rateTime
        + + + + + + + +
        + + + + +
        + Note: failures are anticipated and checked for with assertions while errors are unanticipated. +
        +
        + + + +

        Unit Test Results

        + + + + + +
        Designed for use with PHPUnit2 and Phing.
        +
        +
        + + + + + + +

        Report generated at
        +
        + + + + Name + Tests + Errors + Failures + Time(s) + + + + + + + Name + Tests + Errors + Failures + Time(s) + + + + + + + Name + Status + Type + Time(s) + + + + + + + + + + + Failure + Error + + + + + + + + + + + + + + + + + + + + + Error + + + + + + Failure + + + + Error + + + + Success + + + + + + + + + + + + + + + + + + + + + + + + N/A + + + + + + +

        + + + +
        +
        + + + + + + +
        + + + +
        + + + +
        +
        + + + + + + + + + + + +
        + diff --git a/buildscripts/phing/etc/str.replace.function.xsl b/buildscripts/phing/etc/str.replace.function.xsl new file mode 100644 index 00000000..5d74e86c --- /dev/null +++ b/buildscripts/phing/etc/str.replace.function.xsl @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ERROR: function implementation of str:replace() relies on exsl:node-set(). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/buildscripts/phing/pear/BuildPhingPEARPackageTask.php b/buildscripts/phing/pear/BuildPhingPEARPackageTask.php new file mode 100644 index 00000000..6ac6ad51 --- /dev/null +++ b/buildscripts/phing/pear/BuildPhingPEARPackageTask.php @@ -0,0 +1,270 @@ +. + */ + +require_once 'phing/tasks/system/MatchingTask.php'; +include_once 'phing/types/FileSet.php'; +include_once 'phing/tasks/ext/pearpackage/Fileset.php'; + +/** + * + * @author Hans Lellelid + * @package phing.tasks.ext + * @version $Revision$ + */ +class BuildPhingPEARPackageTask extends MatchingTask { + + /** Base directory for reading files. */ + private $dir; + + private $version; + private $state = 'stable'; + private $notes; + + private $filesets = array(); + + /** Package file */ + private $packageFile; + + public function init() { + include_once 'PEAR/PackageFileManager2.php'; + if (!class_exists('PEAR_PackageFileManager2')) { + throw new BuildException("You must have installed PEAR_PackageFileManager2 (PEAR_PackageFileManager >= 1.6.0) in order to create a PEAR package.xml file."); + } + } + + private function setOptions($pkg){ + + $options['baseinstalldir'] = 'phing'; + $options['packagedirectory'] = $this->dir->getAbsolutePath(); + + if (empty($this->filesets)) { + throw new BuildException("You must use a tag to specify the files to include in the package.xml"); + } + + $options['filelistgenerator'] = 'Fileset'; + + // Some PHING-specific options needed by our Fileset reader + $options['phing_project'] = $this->getProject(); + $options['phing_filesets'] = $this->filesets; + + if ($this->packageFile !== null) { + // create one w/ full path + $f = new PhingFile($this->packageFile->getAbsolutePath()); + $options['packagefile'] = $f->getName(); + // must end in trailing slash + $options['outputdirectory'] = $f->getParent() . DIRECTORY_SEPARATOR; + $this->log("Creating package file: " . $f->getPath(), PROJECT_MSG_INFO); + } else { + $this->log("Creating [default] package.xml file in base directory.", PROJECT_MSG_INFO); + } + + // add install exceptions + $options['installexceptions'] = array( 'bin/phing.php' => '/', + 'bin/pear-phing' => '/', + 'bin/pear-phing.bat' => '/', + ); + + $options['dir_roles'] = array( 'phing_guide' => 'doc', + 'etc' => 'data', + 'example' => 'doc'); + + $options['exceptions'] = array( 'bin/pear-phing.bat' => 'script', + 'bin/pear-phing' => 'script', + 'CREDITS' => 'doc', + 'CHANGELOG' => 'doc', + 'README' => 'doc', + 'TODO' => 'doc'); + + $pkg->setOptions($options); + + } + + /** + * Main entry point. + * @return void + */ + public function main() { + + if ($this->dir === null) { + throw new BuildException("You must specify the \"dir\" attribute for PEAR package task."); + } + + if ($this->version === null) { + throw new BuildException("You must specify the \"version\" attribute for PEAR package task."); + } + + $package = new PEAR_PackageFileManager2(); + + $this->setOptions($package); + + // the hard-coded stuff + $package->setPackage('phing'); + $package->setSummary('PHP5 project build system based on Apache Ant'); + $package->setDescription('PHing Is Not GNU make; it\'s a project build system based on Apache Ant. +You can do anything with it that you could do with a traditional build system like GNU make, and its use of +simple XML build files and extensible PHP "task" classes make it an easy-to-use and highly flexible build framework. +Features include file transformations (e.g. token replacement, XSLT transformation, Smarty template transformations, +etc.), file system operations, interactive build support, SQL execution, and much more.'); + $package->setChannel('pear.phing.info'); + $package->setPackageType('php'); + + $package->setReleaseVersion($this->version); + $package->setAPIVersion($this->version); + + $package->setReleaseStability($this->state); + $package->setAPIStability($this->state); + + $package->setNotes($this->notes); + + $package->setLicense('LGPL', 'http://www.gnu.org/licenses/lgpl.html'); + + // Add package maintainers + $package->addMaintainer('lead', 'hans', 'Hans Lellelid', 'hans@xmpl.org'); + $package->addMaintainer('lead', 'mrook', 'Michiel Rook', 'michiel@trendserver.nl'); + + + + // (wow ... this is a poor design ...) + // + // note that the order of the method calls below is creating + // sub-"release" sections which have specific rules. This replaces + // the platformexceptions system in the older version of PEAR's package.xml + // + // Programmatically, I feel the need to re-iterate that this API for PEAR_PackageFileManager + // seems really wrong. Sub-sections should be encapsulated in objects instead of having + // a "flat" API that does not represent the structure being created.... + + + // creating a sub-section for 'windows' + $package->addRelease(); + $package->setOSInstallCondition('windows'); + $package->addInstallAs('bin/phing.php', 'phing.php'); + $package->addInstallAs('bin/pear-phing.bat', 'phing.bat'); + $package->addIgnoreToRelease('bin/pear-phing'); + + // creating a sub-section for non-windows + $package->addRelease(); + //$package->setOSInstallCondition('(*ix|*ux|darwin*|*BSD|SunOS*)'); + $package->addInstallAs('bin/phing.php', 'phing.php'); + $package->addInstallAs('bin/pear-phing', 'phing'); + $package->addIgnoreToRelease('bin/pear-phing.bat'); + + + // "core" dependencies + $package->setPhpDep('5.0.0'); + $package->setPearinstallerDep('1.4.0'); + + // "package" dependencies + $package->addPackageDepWithChannel( 'optional', 'VersionControl_SVN', 'pear.php.net', '0.3.0alpha1'); + $package->addPackageDepWithChannel( 'optional', 'PHPUnit2', 'pear.php.net', '2.3.0'); + $package->addPackageDepWithChannel( 'optional', 'PhpDocumentor', 'pear.php.net', '1.3.0RC3'); + $package->addPackageDepWithChannel( 'optional', 'Xdebug', 'pear.php.net', '2.0.0beta2'); + $package->addPackageDepWithChannel( 'optional', 'Archive_Tar', 'pear.php.net', '1.3.0'); + $package->addPackageDepWithChannel( 'optional', 'PEAR_PackageFileManager', 'pear.php.net', '1.5.2'); + + // now add the replacements .... + $package->addReplacement('Phing.php', 'pear-config', '@DATA-DIR@', 'data_dir'); + $package->addReplacement('bin/pear-phing.bat', 'pear-config', '@PHP-BIN@', 'php_bin'); + $package->addReplacement('bin/pear-phing.bat', 'pear-config', '@BIN-DIR@', 'bin_dir'); + $package->addReplacement('bin/pear-phing.bat', 'pear-config', '@PEAR-DIR@', 'php_dir'); + $package->addReplacement('bin/pear-phing', 'pear-config', '@PHP-BIN@', 'php_bin'); + $package->addReplacement('bin/pear-phing', 'pear-config', '@BIN-DIR@', 'bin_dir'); + $package->addReplacement('bin/pear-phing', 'pear-config', '@PEAR-DIR@', 'php_dir'); + + // now we run this weird generateContents() method that apparently + // is necessary before we can add replacements ... ? + $package->generateContents(); + + $e = $package->writePackageFile(); + + if (PEAR::isError($e)) { + throw new BuildException("Unable to write package file.", new Exception($e->getMessage())); + } + + } + + /** + * Used by the PEAR_PackageFileManager_PhingFileSet lister. + * @return array FileSet[] + */ + public function getFileSets() { + return $this->filesets; + } + + // ------------------------------- + // Set properties from XML + // ------------------------------- + + /** + * Nested creator, creates a FileSet for this task + * + * @return FileSet The created fileset object + */ + function createFileSet() { + $num = array_push($this->filesets, new FileSet()); + return $this->filesets[$num-1]; + } + + /** + * Set the version we are building. + * @param string $v + * @return void + */ + public function setVersion($v){ + $this->version = $v; + } + + /** + * Set the state we are building. + * @param string $v + * @return void + */ + public function setState($v) { + $this->state = $v; + } + + /** + * Sets release notes field. + * @param string $v + * @return void + */ + public function setNotes($v) { + $this->notes = $v; + } + /** + * Sets "dir" property from XML. + * @param PhingFile $f + * @return void + */ + public function setDir(PhingFile $f) { + $this->dir = $f; + } + + /** + * Sets the file to use for generated package.xml + */ + public function setDestFile(PhingFile $f) { + $this->packageFile = $f; + } + +} + + diff --git a/buildscripts/phing/pear/build.xml b/buildscripts/phing/pear/build.xml new file mode 100644 index 00000000..128dcd03 --- /dev/null +++ b/buildscripts/phing/pear/build.xml @@ -0,0 +1,156 @@ + + + + + + + + + + + This is the latest release of Phing. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Phing version for package + + + + + + + + + + ----------------------------- + | Creating directory layout | + ----------------------------- + + + + + + + + + + + + Phing version ${version} + + + + + + + + + ----------------------------- + | Creating PEAR package.xml | + ----------------------------- + + ... (This step may take some time) ... + + + + + + + + + + + + + + + + + + + + + ----------------------------- + | Creating TAR packages | + ----------------------------- + + + + + + + + + + + + \ No newline at end of file diff --git a/buildscripts/phing/tasks/ManualIndexTask.php b/buildscripts/phing/tasks/ManualIndexTask.php new file mode 100644 index 00000000..1725880f --- /dev/null +++ b/buildscripts/phing/tasks/ManualIndexTask.php @@ -0,0 +1,38 @@ +docdir=$value; + } + + public function setTodir($value) + { + $this->todir=$value; + } + + public function main() + { + $srcdir=realpath(dirname(__FILE__).'/../../../'); + $zend_path = $srcdir.'/demos/quickstart/protected/index'; + set_include_path(get_include_path().PATH_SEPARATOR.realpath($zend_path)); + require_once ('Zend/Search/Lucene.php'); + require_once($srcdir.'/buildscripts/index/api_index.php'); + $api = new api_index($this->todir, realpath($this->docdir)); + $api->create_index(); + } +} + +?> \ No newline at end of file diff --git a/buildscripts/phing/tasks/PradoDocTask.php b/buildscripts/phing/tasks/PradoDocTask.php new file mode 100644 index 00000000..3ab891bd --- /dev/null +++ b/buildscripts/phing/tasks/PradoDocTask.php @@ -0,0 +1,137 @@ +phpdoc=$phpdoc; + } + + /** + * Set the title for the generated documentation + */ + function setTitle($title) + { + $this->title = $title; + } + + /** + * Set the destination directory for the generated documentation + */ + function setDestdir($destdir) + { + $this->destdir = $destdir; + } + + /** + * Set the source path + */ + function setSourcepath(Path $sourcepath) + { + if ($this->sourcepath === NULL) + { + $this->sourcepath = $sourcepath; + } + else + { + $this->sourcepath->append($sourcepath); + } + } + + /** + * Set the output type + */ + function setOutput($output) + { + $this->output = $output; + } + + /** + * Should sources be linked in the generated documentation + */ + function setLinksource($linksource) + { + $this->linksource = $linksource; + } + + function setIgnorelist($ignorelist) + { + $this->ignorelist=$ignorelist; + } + + /** + * Main entrypoint of the task + */ + function main() + { + $arguments = $this->constructArguments(); + exec($this->phpdoc . " " . $arguments, $output, $retval); + } + + /** + * Constructs an argument string for phpDocumentor + */ + private function constructArguments() + { + $arguments = "-q \"on\" "; + + if ($this->title) + { + $arguments.= "-ti \"" . $this->title . "\" "; + } + + if ($this->destdir) + { + $arguments.= "-t \"" . $this->destdir . "\" "; + } + + if ($this->sourcepath !== NULL) + { + $arguments.= "-d \"" . $this->sourcepath->__toString() . "\" "; + } + + if ($this->output) + { + $arguments.= "-o \"" . $this->output . "\" "; + } + + if ($this->linksource) + { + $arguments.= "-s "; + } + + if ($this->parseprivate) + { + $arguments.= "-pp "; + } + + if ($this->ignorelist) + { + $arguments.='-i "'.$this->ignorelist.'" '; + } + + return $arguments; + } +} + +?> \ No newline at end of file diff --git a/buildscripts/phing/tasks/PradoPearTask.php b/buildscripts/phing/tasks/PradoPearTask.php new file mode 100644 index 00000000..5d615084 --- /dev/null +++ b/buildscripts/phing/tasks/PradoPearTask.php @@ -0,0 +1,133 @@ +pkgdir=$value; + } + + function setChannel($value) + { + $this->channel=$value; + } + + function setVersion($value) + { + $this->version=$value; + } + + function setState($value) + { + $this->state=$value; + } + + function setCategory($value) + { + $this->category=$value; + } + + function setPackage($value) + { + $this->package=$value; + } + + function setSummary($value) + { + $this->summary=$value; + } + + function setPkgdescription($value) + { + $this->pkgdescription=$value; + } + + function setNotes($value) + { + $this->notes=$value; + } + + function setLicense($value) + { + $this->license=$value; + } + + /** + * Main entrypoint of the task + */ + function main() + { + $pkg = new PEAR_PackageFileManager2(); + + $e = $pkg->setOptions( + array( + 'baseinstalldir' => 'prado', + 'packagedirectory' => $this->pkgdir, + 'pathtopackagefile' => $this->pkgdir, + 'filelistgenerator' => 'file', + 'simpleoutput' => true, + 'ignore' => array(), + 'dir_roles' => + array( + 'docs' => 'doc', + 'examples' => 'doc', + 'framework' => 'php', + 'framework/js' => 'doc', + 'framework/3rdParty' => 'doc', + ), + 'exceptions' => + array( + 'requirements.php' => 'doc', + ), + ) + ); + + // PEAR error checking + if (PEAR::isError($e)) + die($e->getMessage()); + $pkg->setPackage($this->package); + $pkg->setSummary($this->summary); + $pkg->setDescription($this->pkgdescription); + $pkg->setChannel($this->channel); + + $pkg->setReleaseStability($this->state); + $pkg->setAPIStability($this->state); + $pkg->setReleaseVersion($this->version); + $pkg->setAPIVersion($this->version); + + $pkg->setLicense($this->license); + $pkg->setNotes($this->notes); + $pkg->setPackageType('php'); + $pkg->setPhpDep('5.0.0'); + $pkg->setPearinstallerDep('1.4.2'); + + $pkg->addRelease(); + $pkg->addMaintainer('lead','qxue','Qiang (Charlie) Xue','qiang.xue@gmail.com'); + + $test = $pkg->generateContents(); + + $e = $pkg->writePackageFile(); + + if (PEAR::isError($e)) + echo $e->getMessage(); + } +} + +?> \ No newline at end of file diff --git a/buildscripts/phing/tasks/PradoTestTask.php b/buildscripts/phing/tasks/PradoTestTask.php new file mode 100644 index 00000000..ba1e06be --- /dev/null +++ b/buildscripts/phing/tasks/PradoTestTask.php @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/buildscripts/phing/tasks/PradoVersionTask.php b/buildscripts/phing/tasks/PradoVersionTask.php new file mode 100644 index 00000000..911b68d4 --- /dev/null +++ b/buildscripts/phing/tasks/PradoVersionTask.php @@ -0,0 +1,56 @@ +addProperty('prado.version',$this->getPradoVersion()); + $this->addProperty('prado.revision',$this->getPradoRevision()); + if(substr(PHP_OS, 0, 3) == 'WIN') + $this->addProperty('prado.winbuild','true'); + else + $this->addProperty('prado.winbuild','false'); + } + + /** + * @return string Prado version + */ + private function getPradoVersion() + { + $coreFile=dirname(__FILE__).'/../../../framework/PradoBase.php'; + if(is_file($coreFile)) + { + $contents=file_get_contents($coreFile); + $matches=array(); + if(preg_match('/public static function getVersion.*?return \'(.*?)\'/ms',$contents,$matches)>0) + return $matches[1]; + } + return 'unknown'; + } + + /** + * @return string Prado SVN revision + */ + private function getPradoRevision() + { + $svnPath=dirname(__FILE__).'/../../../.svn'; + if(is_file($svnPath.'/all-wcprops')) + $propFile=$svnPath.'/all-wcprops'; + else if(is_file($svnPath.'/dir-wcprops')) + $propFile=$svnPath.'/dir-wcprops'; + else + return 'unknown'; + $contents=file_get_contents($propFile); + if(preg_match('/\\/repos\\/prado\\/\\!svn\\/ver\\/(\d+)\\//ms',$contents,$matches)>0) + return $matches[1]; + else + return 'unknown'; + } +} + +?> \ No newline at end of file diff --git a/buildscripts/phing/tasks/QuickstartIndexTask.php b/buildscripts/phing/tasks/QuickstartIndexTask.php new file mode 100644 index 00000000..f3107fd3 --- /dev/null +++ b/buildscripts/phing/tasks/QuickstartIndexTask.php @@ -0,0 +1,32 @@ +todir=$value; + } + + public function main() + { + $srcdir=realpath(dirname(__FILE__).'/../../../'); + $zend_path = $srcdir.'/demos/quickstart/protected/index'; + set_include_path(get_include_path().PATH_SEPARATOR.realpath($zend_path)); + require_once ('Zend/Search/Lucene.php'); + + require_once($srcdir.'/buildscripts/index/quickstart_index.php'); + $quickstart_source = $srcdir.'/buildscripts/texbuilder/pages.php'; + $quickstart_base = $srcdir.'/demos/quickstart/protected/pages/'; + $quickstart = new quickstart_index($this->todir, realpath($quickstart_base), realpath($quickstart_source)); + $quickstart->create_index(); + } +} + +?> \ No newline at end of file diff --git a/buildscripts/texbuilder/quickstart.tex b/buildscripts/texbuilder/quickstart.tex index ee3010fe..35ba86a5 100644 --- a/buildscripts/texbuilder/quickstart.tex +++ b/buildscripts/texbuilder/quickstart.tex @@ -42,10 +42,10 @@ %----------------- TITLE -------------- -\title{\Huge \bfseries Prado v3.0.1 Quick Start Tutorial +\title{\Huge \bfseries PRADO v3.0.2 Quickstart Tutorial \thanks{Copyright 2005-2006. All Rights Reserved.} } -\author{Qiang Xue, Wei Zhuo} +\author{Qiang Xue and Wei Zhuo} \date{\today} -- cgit v1.2.3