cvs: pear /CodeGen_PECL .cvsignore BUGS BrainDump ChangeLog Command.php Element.php Extension.php ExtensionParser.php LICENSE.txt Maintainer.php
README RFC_proto.txt Release.php TODO extension.dtd manual.html manual.xml package.xml pecl-gen /CodeGen_PECL/Dependency Header.php Lib.php With.php
/CodeGen_PECL/Element Class.php Constant.php Function.php Global.php Ini.php Logo.php Method.php Property.php Resource.php Stream.php Test.php
/CodeGen_PECL/examples logo.xml

From: Date: Mon, 18 Jul 2005 08:12:37 +0000
Subject: cvs: pear /CodeGen_PECL .cvsignore BUGS BrainDump ChangeLog Command.php Element.php Extension.php ExtensionParser.php LICENSE.txt Maintainer.php
README RFC_proto.txt Release.php TODO extension.dtd manual.html manual.xml package.xml pecl-gen /CodeGen_PECL/Dependency Header.php Lib.php With.php
/CodeGen_PECL/Element Class.php Constant.php Function.php Global.php Ini.php Logo.php Method.php Property.php Resource.php Stream.php Test.php
/CodeGen_PECL/examples logo.xml
Groups: php.pear.cvs 
Request: Send a blank email to pear-cvs+get-33099@lists.php.net to get a copy of this message
hholzgra Mon Jul 18 04:12:37 2005 EDT Added files: /pear/CodeGen_PECL .cvsignore BUGS BrainDump ChangeLog Command.php Element.php Extension.php ExtensionParser.php LICENSE.txt Maintainer.php README RFC_proto.txt Release.php TODO extension.dtd manual.html manual.xml package.xml pecl-gen /pear/CodeGen_PECL/Dependency Header.php Lib.php With.php /pear/CodeGen_PECL/Element Class.php Constant.php Function.php Global.php Ini.php Logo.php Method.php Property.php Resource.php Stream.php Test.php /pear/CodeGen_PECL/examples logo.xml Log: Initial commit of CodeGen_PECL, formerly a part of PECL_Gen

http://cvs.php.net/co.php/pear/CodeGen_PECL/.cvsignore?r=1.1&p=1 Index: pear/CodeGen_PECL/.cvsignore +++ pear/CodeGen_PECL/.cvsignore *~ PECL_GEN*.tgz dumpster http://cvs.php.net/co.php/pear/CodeGen_PECL/Command.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Command.php +++ pear/CodeGen_PECL/Command.php <?php /** * Command wrapper class * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Command.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ /** * includes */ require_once "CodeGen/Command.php"; require_once "CodeGen/PECL/Extension.php"; require_once "CodeGen/PECL/ExtensionParser.php"; /** * Command wrapper class * * This class wraps up the functionality needed for the * command line script. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Command extends CodeGen_Command { /** * Command constructor * * @param object Extension to work on */ function __construct(CodeGen_Extension $extension) { parent::__construct($extension); if ($this->options->have("linespecs", "l")) { $this->extension->setLinespecs(true); } } /** * Add pecl-gen specific command line options * * @return array extended options */ function commandOptions() { list($shortOptions, $longOptions) = parent::commandOptions(); $shortOptions .= "l"; $longOptions= array_merge($longOptions, array("extname=", "full-xml", "function=", "linespecs", "no-help", "proto=", "skel=" , "stubs=", "xml==")); return array($shortOptions, $longOptions); } /** * Show usage/help information * * @param string otpional additional message */ function showUsage($message = false) { $fp = fopen("php://stderr", "w"); if ($message) fputs($fp, "$message\n\n"); fputs($fp, "Usage: pecl-gen [-h] [--force] [--experimental] [--version] [--extname=name] [--proto=file] [--skel=dir] [--stubs=file] [--no-help] [--xml[=file]] [--full-xml] [--function=proto] [specfile.xml] -h|--help this message -f|--force overwrite existing directories -d|--dir output directory (defaults to extension name) -l|--linespecs generate #line specs -x|--experimental deprecated --function create a function skeleton from a proto right away --version show version info the following options are inherited from ext_skel: --extname=module module is the name of your extension --proto=file file contains prototypes of functions to create --xml generate xml documentation to be added to phpdoc-cvs these wait for functionality to be implemented and are ignored for now ... --stubs=file generate only function stubs in file --no-help don't try to be nice and create comments in the code and helper functions to test if the module compiled these are accepted for backwards compatibility reasons but not used ... --full-xml generate xml documentation for a self-contained extension (this was also a no-op in ext_skel) --skel=dir path to the skeleton directory (skeleton stuff is now self-contained) "); fclose($fp); } /** * Generate just a single function stub file * */ function singleFunction() { $func = new CodeGen_PECL_Element_Function; $func->set_role("public"); $err = $func->setProto(trim($this->options->value("function"))); if (PEAR::isError($err)) { terminate($err->get_message()); } $err = $this->extension->addFunction($func); if (PEAR::isError($err)) { terminate($err->get_message()); } echo $this->extension->publicFunctionsC(); echo "\n\n/*----------------------------------------------------------------------*/\n\n"; foreach ($this->extension->functions as $name => $function) { echo sprintf("\tPHP_FE(%-20s, NULL)\n",$name); } echo "\n\n/*----------------------------------------------------------------------*/\n\n"; foreach ($this->extension->functions as $name => $function) { echo "PHP_FUNCTION($name);\n"; } } /** * ext-skel compatibility mode * */ function extSkelCompat() { $extname = $this->options->value("extname"); $err = $this->extension->setName($extname); if (PEAR::isError($err)) { $command->terminate($err->getMessage()); } if ($this->options->have("proto")) { $proto_file = $this->options->value("proto"); if (!file_exists($proto_file) || !is_readable($proto_file)) { $command->terminate("cannot open proto file"); } foreach (file($proto_file) as $line) { $func = new CodeGen_PECL_Element_Function; $func->setRole("public"); $err = $func->setProto(trim($line)); if (PEAR::isError($err)) { $command->terminate($err->getMessage()); } $err = $this->extension->addFunction($func); if (PEAR::isError($err)) { $command->terminate($err->getMessage()); } } } if ($this->options->have("stubs")) { $stubname = $this->options->value("stubs"); if (file_exists("$stubname") && !$this->options->have("f", "force")) { $command->terminate("'$stubname' already exists (use '--force' to overwrite)"); } $fp = fopen($stubname, "w"); fputs($fp, $this->extension->publicFunctionsC()); fputs($fp, "\n\n/*----------------------------------------------------------------------*/\n\n"); foreach ($this->extension->functions as $name => $function) { fputs($fp, sprintf("\tPHP_FE(%-20s, NULL)\n",$name)); } fputs($fp, "\n\n/*----------------------------------------------------------------------*/\n\n"); foreach ($this->extension->functions as $name => $function) { fputs($fp, "PHP_FUNCTION($name);\n"); } fclose($fp); echo "$stubname successfully written\n"; } else { if (file_exists("./$extname") && !$this->options->have("f", "force")) { $command->terminate("'$extname' already exists, can't create directory (use '--force' to override)"); } $err = System::mkdir($extname); if (PEAR::isError($err)) { $command->terminate($err->getMessage()); } $err = $this->extension->generateSource("./$extname"); if (PEAR::isError($err)) { $command->terminate($err->getMessage()); } if ($this->options->have("xml")) { $manpath = "$extname/manual/". str_replace('_', '-', $extname); $err = System::mkdir("-p $manpath"); if (PEAR::isError($err)) { $command->terminate($err->getMessage()); } $err = $this->extension->generateDocumentation($manpath); if (PEAR::isError($err)) { $command->terminate($err->getMessage()); } } $this->extension->write_readme("./$extname"); if (!$this->options->have("quiet")) { echo $this->extension->successMsg(); } } } } http://cvs.php.net/co.php/pear/CodeGen_PECL/Element.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Element.php +++ pear/CodeGen_PECL/Element.php <?php /** * Abstract base class for all PHP code elements * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Element.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ require_once "CodeGen/Element.php"; /** * Abstract base class for all PHP code elements * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ abstract class CodeGen_PECL_Element extends CodeGen_Element { /** * Checks whether a string is a valid PHP type name and returns the official name * * @access public * @param string Type name * @return string The official type name or boolean false if not a type */ function isType($name) { static $types = array("void" => "void", "bool" => "bool", "boolean" => "bool", "int" => "int", "integer" => "int", "float" => "float", "double" => "float", "real" => "float", "string" => "string", "array" => "array", "object" => "object", "resource" => "resource", "mixed" => "mixed", "callback" => "callback", "stream" => "stream" ); if (isset($types[$name])) { return $types[$name]; } else { return false; } } /** * Checks whether a string is a reserved name * * @access public * @param string name * @return bool true if reserved */ function isKeyword($name) { // these are taken from zend_language_scanner.l static $reserved = array( "abstract", "and", "array", "as", "break", "case", "catch", "class", "const", "continue", "declare", "default", "die", "do", "echo", "else", "elseif", "empty", "enddeclare", "endfor", "endforeach", "endif", "endwhile", "eval", "exit", "extends", "final", "for", "foreach", "function", "global", "if", "implements", "include", "include_once", "instanceof", "interface", "isset", "list", "new", "or", "print", "private", "protected", "public", "require", "require_once", "return", "static", "throw", "try", "unset", "unset", "use", "var", "while", "xor", ); foreach ($reserved as $keyword) { if (!strcasecmp($keyword, $name)) { return true; } } return false; } /** * Generate Editor settings block for C source files * * @access public * @return string Editor settings comment block */ static function cCodeEditorSettings() { return ' /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ '; } /** * Generate Editor settings block for documentation files * * @access public * @param int Directory nesting depth of target file (default: 3) * @return string Editor settings comment block */ static function docEditorSettings($level=3) { return ' <!-- Keep this comment at the end of the file Local'.' variables: mode: sgml sgml-omittag:t sgml-shorttag:t sgml-minimize-attributes:nil sgml-always-quote-attributes:t sgml-indent-step:1 sgml-indent-data:t indent-tabs-mode:nil sgml-parent-document:nil sgml-default-dtd-file:"'.str_repeat("../",$level).'manual.ced" sgml-exposed-tags:nil sgml-local-catalogs:nil sgml-local-ecat-files:nil End: vim600: syn=xml fen fdm=syntax fdl=2 si vim: et tw=78 syn=sgml vi: ts=1 sw=1 --> '; } } ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/Extension.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Extension.php +++ pear/CodeGen_PECL/Extension.php <?php /** * A class that generates PECL extension soure and documenation files * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Extension.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ /** * includes */ require_once "System.php"; require_once "CodeGen/Extension.php"; require_once "CodeGen/PECL/Release.php"; require_once "CodeGen/PECL/Element.php"; require_once "CodeGen/PECL/Element/Constant.php"; require_once "CodeGen/PECL/Element/Function.php"; require_once "CodeGen/PECL/Element/Resource.php"; require_once "CodeGen/PECL/Element/Ini.php"; require_once "CodeGen/PECL/Element/Global.php"; require_once "CodeGen/PECL/Element/Logo.php"; require_once "CodeGen/PECL/Element/Test.php"; require_once "CodeGen/PECL/Element/Class.php"; require_once "CodeGen/PECL/Element/Stream.php"; require_once "CodeGen/PECL/Dependency/With.php"; require_once "CodeGen/PECL/Dependency/Lib.php"; require_once "CodeGen/PECL/Dependency/Header.php"; /** * A class that generates PECL extension soure and documenation files * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Extension extends CodeGen_Extension { /** * Current version number * * @access public * @return string version */ static function version() { return "0.9.0rc5"; } /** * Copyright message * * @access public * @return string version */ static function copyright() { return "Copyright (c) 2003-2005 Hartmut Holzgraefe"; } // {{{ member variables /** * The public PHP functions defined by this extension * * @var array */ var $functions = array(); /** * The extensions internal functions like MINIT * * @var array */ var $internalFunctions = array(); /** * The constants defined by this extension * * @var array */ var $constants = array(); /** * The PHP classes defined by this extension * * @var array */ var $classes = array(); /** * The extensions php.ini parameters * * @var array */ var $phpini = array(); /** * The extensions internal global variables * * @var array */ var $globals = array(); /** * The PHP resources defined by this extension * * @var array */ var $resources = array(); /** * The package files created by this extension * * @var array */ var $packageFiles = array(); /** * Code snippets * * @var array */ var $code = array(); /** * Makefile fragments * * @var array */ var $makefragment = array(); /** * Custom test cases * * @var array */ var $testcases = array(); /** * phpinfo logos * * @var string * @access private */ var $logos = array(); /** * Makefile fragments * * @var array * @access private */ var $makefragments = array(); /** * config.m4 fragments * * @var array * @access private */ var $configfragments = array("top"=>array(), "bottom"=>array()); /** * generate #line specs? * * @var bool * @access private */ var $linespecs = false; /** * PHP Streams * * @var array * @access private */ var $streams = array(); /** * External libraries * * @var array * @access private */ var $libs = array(); /** * External header files * * @var array * @access private */ var $headers = array(); /** * --with configure options * * @var array * @access private */ var $with = array(); // }}} // {{{ constructor /** * The constructor * * @access public */ function __construct() { $this->release = new CodeGen_PECL_Release; $this->platform = new CodeGen_Tools_Platform("all"); } // }}} /** * Add verbatim code snippet to extension * * @access public * @param string which file to put the code to * @param string where in the file the code should be put * @param string the actual code */ function addCode($role, $position, $code) { if (!in_array($role, array("header", "code"))) { return PEAR::raiseError("'$role' is not a valid custom code role"); } if (!in_array($position, array("top", "bottom"))) { return PEAR::raiseError("'$position' is not a valid custom code position"); } $this->code[$role][$position][] = $code; } function addLib($lib) { // TODO check dups $this->libs[$lib->getName()] = $lib; } function addHeader($header) { // TODO check dups $this->headers[$header->getName()] = $header; } // {{{ member adding functions /** * Add a function to the extension * * @access public * @param object a function object */ function addFunction($function) { if (!is_a($function, "CodeGen_PECL_Element_Function")) { return PEAR::raiseError("argument is not CodeGen_PECL_Element_Function"); } $role = $function->getRole(); switch ($role) { case "public": if (isset($this->functions[$function->name])) { return PEAR::raiseError("public function '{$function->name}' has been defined before"); } $this->functions[$function->name] = $function; return true; case "private": return PEAR::raiseError("private functions are no longer supported, use <code> sections instead"); case "internal": if (isset($this->functions[$function->name])) { return PEAR::raiseError("internal '{$function->name}' has been defined before"); } $this->internalFunctions[$function->name] = $function; return true; default: return PEAR::raiseError("unnokwn function role '$role'"); } } /** * Add a PHP constant to the extension * * @access public * @param object a constant object */ function addConstant($constant) { if (isset($this->constants[$constant->name])) { return PEAR::raiseError("constant '{$constant->name}' has been defined before"); } $this->constants[$constant->name] = $constant; return true; } /** * Add a PHP ini directive * * @access public * @param object a phpini object */ function addPhpIni($phpini) { if (isset($this->phpini[$phpini->name])) { return PEAR::raiseError("php.ini directive '{$phpini->name}' has been defined before"); } $this->phpini[$phpini->name] = $phpini; return true; } /** * Add a internal global variable * * @access public * @param object a global object */ function addGlobal($global) { if (isset($this->globals[$global->name])) { return PEAR::raiseError("global '{$global->name}' has been defined before"); } $this->globals[$global->name] = $global; return true; } /** * Add a PHP resource type * * @access public * @param object a resource object */ function addResource($resource) { if (isset($this->resources[$resource->name])) { return PEAR::raiseError("resource type '{$resource->name}' has been defined before"); } $this->resources[$resource->name] = $resource; return true; } /** * Add a PHP class to the extension * * @access public * @param object a class object */ function addClass($class) { if (isset($this->classes[$class->getName()])) { return PEAR::raiseError("class '".$class->getName()."' has been defined before"); } $this->classes[$class->getName()] = $class; return true; } /** * Add a PHP stream wrapper to the extension * * @access public * @param object a stream wrapper object */ function addStream($stream) { if (isset($this->streams[$stream->getName()])) { return PEAR::raiseError("stream '".$stream->getName()."' has been defined before"); } $this->streams[$stream->getName()] = $stream; return true; } /** * Add a package file by type and path * * @access public * @param string type * @param string path * @returns bool success state */ function addPackageFile($type, $path) { $basename = basename($path); if (isset($this->packageFiles[$type][$basename])) { return PEAR::raiseError("duplicate distribution file name '$basename'"); } $this->packageFiles[$type][$basename] = $path; return true; } /** * Add a --with configure option * * @access public * @param object 'With' object * @returns bool */ function addWith($with) { if (isset($this->with[$with->name])) { return PEAR::raiseError("--with-{$with->name} declared twice"); } $this->with[$with->name] = $with; return true; } /** * Add a source file to be copied to the extension dir * * @access public * @param string path */ function addSourceFile($name) { // TODO catch errors returned from addPackageFile $filename = realpath($name); if (!is_file($filename)) { return PEAR::raiseError("'$name' is not a valid file"); } if (!is_readable($filename)) { return PEAR::raiseError("'$name' is not readable"); } $pathinfo = pathinfo($filename); $ext = $pathinfo["extension"]; switch ($ext) { case 'c': $this->addConfigFragment("AC_PROG_CC"); $this->addPackageFile('code', $filename); break; case 'cpp': case 'cxx': case 'c++': $this->addConfigFragment("AC_PROG_CXX"); $this->addConfigFragment("AC_LANG([C++])"); $this->addPackageFile('code', $filename); break; case 'l': case 'flex': $this->addConfigFragment("AM_PROG_LEX"); $this->addPackageFile('code', $filename); break; case 'y': case 'bison': $this->addConfigFragment("AM_PROG_YACC"); $this->addPackageFile('code', $filename); break; default: break; } return $this->addPackageFile('copy', $filename); } /** * Add phpinfo logo * * @access public * @param object the logo */ function addLogo($logo) { if (isset($this->logos[$logo->name])) { return PEAR::raiseError("logo '{$logo->name}' already defined"); } $this->logos[$logo->name] = $logo; return true; } /** * Add makefile fragment * * @access public * @param string */ function addMakeFragment($text) { $this->makefragment[] = $text; return true; } /** * Add config.m4 fragment * * @access public * @param string */ function addConfigFragment($text, $position="top") { if (!in_array($position, array("top", "bottom"))) { return PEAR::raiseError("'$position' is not a valid config snippet position"); } $this->configfragments[$position][] = $text; return true; } /** * Generate #line specs? * * @access public * @param bool */ function setLinespecs($state) { $this->linespecs = $state; } // }}} // {{{ output generation /** * Create the extensions including * * @access public * @param string Directory to create (default is ./$this->name) */ function createExtension($dirpath = false, $force = false) { // default: create dir in current working directory, // dirname is the extensions base name if (!is_string($dirpath) || $dirpath == "") { $dirpath = "./" . $this->name; } // purge and create extension directory if ($dirpath !== ".") { if (!$force && file_exists($dirpath)) { return PEAR::raiseError("'$dirpath' already exists, can't create that directory (use '--force' to override)"); } else if (!@System::mkdir("-p $dirpath")) { return PEAR::raiseError("can't create '$dirpath'"); } } // make path absolute to be independant of working directory changes $this->dirpath = realpath($dirpath); echo "Creating '{$this->name}' extension in '$dirpath'\n"; // generate complete source code $this->generateSource(); // copy additional source files if (isset($this->packageFiles['copy'])) { foreach ($this->packageFiles['copy'] as $basename => $filepath) { copy($filepath, $this->dirpath."/".$basename); } } // generate README file $this->writeReadme(); // generate DocBook XML documantation for PHP manual $manpath = $this->dirpath . "/manual/" . str_replace('_', '-', $this->name); if (!@System::mkdir("-p $manpath")) { return PEAR::raiseError("can't create '$manpath'", E_USER_ERROR); } $this->generateDocumentation($manpath); } /** * Create the extensions code soure and project files * * @access public */ function generateSource() { // generate source and header files $this->writeHeaderFile(); $this->writeCodeFile(); foreach($this->logos as $logo) { $fp = fopen("{$this->dirpath}/{$logo->name}_logos.h", "w"); fwrite($fp, CodeGen_Tools_Indent::tabify($logo->hCode())); fclose($fp); } // generate project files for configure (unices and similar platforms like cygwin) if ($this->platform->test("unix")) { $this->writeConfigM4(); } // generate project files for Windows platform (VisualStudio/C++ V6) if ($this->platform->test("windows")) { $this->writeMsDevStudioDsp(); $this->writeConfigW32(); } // generate .cvsignore file entries $this->writeDotCvsignore(); // generate EXPERIMENTAL file for unstable release states $this->writeExperimental(); // generate CREDITS file $this->writeCredits(); // generate LICENSE file if license given if ($this->license) { $this->license->writeToFile($this->dirpath."/LICENSE"); $this->files['doc'][] = "LICENSE"; } // generate PEAR/PECL package.xml file $this->writePackageXml(); // generate test case templates $this->writeTestFiles(); } // {{{ docbook documentation /** * Create the extension documentation DocBook XML files * * @access public * @param string Directory to write to */ function generateDocumentation($docdir) { $idName = str_replace('_', '-', $this->name); $fp = fopen("$docdir/reference.xml", "w"); fputs($fp, "<?xml version='1.0' encoding='iso-8859-1'?> <!-- ".'$'."Revision: 1.1 $ --> <reference id='ref.$idName'> <title>{$this->summary}</title> <titleabbrev>$idName</titleabbrev> <partintro> <section id='$idName.intro'> &reftitle.intro; <para> {$this->description} </para> </section> &reference.$idName.configure; <section id='$idName.resources'> &reftitle.resources; "); if (empty($this->resources)) { fputs($fp, " &no.resource;\n"); } else { foreach ($this->resources as $resource) { fputs($fp, $resource->docEntry($idName)); } } fputs($fp, " </section> <section id='$idName.constants'> &reftitle.constants; "); if (empty($this->constants)) { fputs($fp, " &no.constants;\n"); } else { fputs($fp, CodeGen_PECL_Element_Constant::docHeader($idName)); foreach ($this->constants as $constant) { fputs($fp, $constant->docEntry($idName)); } fputs($fp, CodeGen_PECL_Element_Constant::docFooter()); } fputs($fp, " </section> </partintro> &reference.$idName.functions; </reference> "); fputs($fp, CodeGen_PECL_Element::docEditorSettings()); fclose($fp); // configure options and dependencies have their own file $fp = fopen("$docdir/configure.xml","w"); fputs($fp,"\n <section id='$idName.requirements'>\n &reftitle.required;\n"); if (empty($this->libs) && empty($this->headers)) { fputs($fp, " &no.requirement;\n"); } else { // TODO allow custom text if (isset($this->libs)) { $libs = array(); foreach ($this->libs as $lib) { $libs[] = $lib->getName(); } $ies = count($libs)>1 ? "ies" :"y"; fputs($fp, "<para>This extension requires the following librar$ies: ".join(",", $libs)."</para>\n"); } if (isset($this->headers)) { $headers = array(); foreach ($this->headers as $header) { $headers[] = $header->getName(); } $s = count($headers)>1 ? "s" : ""; fputs($fp, "<para>This extension requires the following header$s: ".join(",", $headers)."</para>\n"); } } fputs($fp, "\n </section>\n\n"); fputs($fp,"\n <section id='$idName.install'>\n &reftitle.install;\n"); if (empty($this->with)) { fputs($fp, " &no.install;\n"); } else { foreach ($this->with as $with) { if (isset($with->summary)) { if (strstr($with->summary, "<para>")) { fputs($fp, $with->summary); } else { fputs($fp, " <para>\n".rtrim($with->summary)."\n </para>\n"); } } else { // TODO default text } } } fputs($fp, "\n </section>\n\n"); fputs($fp,"\n <section id='$idName.configuration'>\n &reftitle.runtime;\n"); if (empty($this->phpini)) { fputs($fp, " &no.config;\n"); } else { fputs($fp, CodeGen_PECL_Element_Ini::docHeader($this->name)); foreach ($this->phpini as $phpini) { fputs($fp, $phpini->docEntry($idName)); } fputs($fp, CodeGen_PECL_Element_Ini::docFooter()); } fputs($fp, "\n </section>\n\n"); fputs($fp, CodeGen_PECL_Element::docEditorSettings()); fclose($fp); @mkdir("$docdir/functions"); foreach ($this->functions as $name => $function) { $filename = $docdir . "/functions/" . strtolower(str_replace("_", "-", $name)) . ".xml"; $funcfile = fopen($filename, "w"); fputs($funcfile, $function->docEntry($idName)); fclose($funcfile); } } // }}} // {{{ extension entry /** * Create the module entry code for this extension * * @access private * @return string zend_module_entry code fragment */ function generateExtensionEntry() { $name = $this->name; $upname = strtoupper($this->name); $code = " /* {{{ {$name}_module_entry */ zend_module_entry {$name}_module_entry = { STANDARD_MODULE_HEADER, \"$name\", {$name}_functions, PHP_MINIT($name), /* Replace with NULL if there is nothing to do at php startup */ PHP_MSHUTDOWN($name), /* Replace with NULL if there is nothing to do at php shutdown */ PHP_RINIT($name), /* Replace with NULL if there is nothing to do at request start */ PHP_RSHUTDOWN($name), /* Replace with NULL if there is nothing to do at request end */ PHP_MINFO($name), \"".$this->release->version."\", STANDARD_MODULE_PROPERTIES }; /* }}} */ "; $code .= "#ifdef COMPILE_DL_$upname\n"; if ($this->language == "cpp") $code .= "extern \"C\" {\n"; $code .= "ZEND_GET_MODULE($name)\n"; if ($this->language == "cpp") $code .= "} // extern \"C\"\n"; $code .= "#endif\n\n"; return $code; } // }}} // {{{ globals and ini /** * Create the module globals c code fragment * * @access private * @return string module globals code fragment */ function generateGlobalsC() { if (empty($this->globals)) return ""; $code = "\n/* {{{ globals and ini entries */\n"; $code .= "ZEND_DECLARE_MODULE_GLOBALS({$this->name})\n\n"; if (!empty($this->phpini)) { $code .= CodeGen_PECL_Element_Ini::cCodeHeader($this->name); foreach ($this->phpini as $phpini) { $code .= $phpini->cCode($this->name); } $code .= CodeGen_PECL_Element_Ini::cCodeFooter($this->name); } if (!empty($this->globals)) { $code .= CodeGen_PECL_Element_Global::cCodeHeader($this->name); foreach ($this->globals as $global) { $code .= $global->cCode($this->name); } $code .= CodeGen_PECL_Element_Global::cCodeFooter($this->name); } $code .= "/* }}} */\n\n"; return $code; } /** * Create the module globals c header file fragment * * @access private * @return string module globals code fragment */ function generateGlobalsH() { if (empty($this->globals)) return ""; $code = CodeGen_PECL_Element_Global::hCodeHeader($this->name); foreach ($this->globals as $global) { $code .= $global->hCode($this->name); } $code .= CodeGen_PECL_Element_Global::hCodeFooter($this->name); return $code; } // }}} // {{{ /** * Create global function registration * * @access private * @return string function registration code fragments */ function generateFunctionRegistrations() { $code = "/* {{{ {$this->name}_functions[] */\n"; $code .= "function_entry {$this->name}_functions[] = {\n"; foreach ($this->functions as $function) { $code .= sprintf(" PHP_FE(%-20s, NULL)\n",$function->name); } foreach ($this->classes as $class) { foreach ($class->methods as $method) { $proceduralName = $method->getProceduralName(); if ($proceduralName) { $code .= sprintf(" ZEND_FALIAS(%s_%s, %s, NULL)\n", $class->getName(), $method->getName(). $proceduralName() ); } } } $code .= " { NULL, NULL, NULL }\n"; $code .= "};\n/* }}} */\n\n"; return $code; } // }}} // {{{ /** * Create global class registration code and functions * * @access private * @return string class registration code fragments */ function generateClassRegistrations() { if (empty($this->classes)) return ""; $code = "/* {{{ classes */\n"; foreach ($this->classes as $class) { $code .= $class->globalCode($this); } $code .= "/* }}} */\n\n"; return $code; } // }}} // {{{ license and authoers /** * Create the license part of the source file header comment * * @access private * @return string code fragment */ function getLicense() { $code = "/*\n"; $code.= " +----------------------------------------------------------------------+\n"; if (is_object($this->license)) { $code.= $this->license->getComment(); } else { $code.= sprintf(" | unknown license: %-52s |\n", $this->license); } $code.= " +----------------------------------------------------------------------+\n"; foreach ($this->authors as $author) { $code.= $author->comment(); } $code.= " +----------------------------------------------------------------------+\n"; $code.= "*/\n\n"; $code.= "/* $ Id: $ */ \n\n"; return $code; } // }}} // {{{ header file /** * Write the complete C header file * * @access private * @param string directory to write to */ function writeHeaderFile() { $filename = "php_{$this->name}.h"; $upname = strtoupper($this->name); ob_start(); echo $this->getLicense(); echo "#ifndef PHP_{$upname}_H\n"; echo "#define PHP_{$upname}_H\n\n"; foreach ($this->headers as $header) { echo $header->hCode(true); } echo "#ifdef __cplusplus\n"; echo "extern \"C\" {\n"; echo "#endif\n"; echo ' #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <php.h> #ifdef HAVE_'.$upname.' #include <php_ini.h> #include <SAPI.h> #include <ext/standard/info.h> '; echo "#ifdef __cplusplus\n"; echo "} // extern \"C\" \n"; echo "#endif\n"; foreach ($this->headers as $header) { echo $header->hCode(false); } if (isset($this->code["header"]["top"])) { foreach ($this->code["header"]["top"] as $code) { echo CodeGen_Tools_Indent::indent(0, $code); } } echo "#ifdef __cplusplus\n"; echo "extern \"C\" {\n"; echo "#endif\n"; echo " extern zend_module_entry {$this->name}_module_entry; #define phpext_{$this->name}_ptr &{$this->name}_module_entry #ifdef PHP_WIN32 #define PHP_{$upname}_API __declspec(dllexport) #else #define PHP_{$upname}_API #endif PHP_MINIT_FUNCTION({$this->name}); PHP_MSHUTDOWN_FUNCTION({$this->name}); PHP_RINIT_FUNCTION({$this->name}); PHP_RSHUTDOWN_FUNCTION({$this->name}); PHP_MINFO_FUNCTION({$this->name}); #ifdef ZTS #include \"TSRM.h\" #endif #define FREE_RESOURCE(resource) zend_list_delete(Z_LVAL_P(resource)) "; echo $this->generateGlobalsH(); echo "\n"; foreach ($this->functions as $name => $function) { echo "PHP_FUNCTION($name);\n"; } foreach ($this->streams as $name => $stream) { echo CodeGen_Tools_Indent::indent(1, $stream->hCode()); } echo "#ifdef __cplusplus\n"; echo "} // extern \"C\" \n"; echo "#endif\n"; echo "\n"; // write #defines for <constant>s $defines = ""; foreach ($this->constants as $constant) { $defines.= $constant->hCode($this); } if ($defines !== "") { echo "/* mirrored PHP Constants */\n"; echo $defines; echo "\n"; } // add bottom header snippets if (isset($this->code["header"]["bottom"])) { echo "/* 'bottom' header snippets*/\n"; foreach ($this->code["header"]["bottom"] as $code) { echo CodeGen_Tools_Indent::indent(0, $code); } echo "\n"; } echo "#endif /* PHP_HAVE_{$upname} */\n\n"; echo "#endif /* PHP_{$upname}_H */\n\n"; echo CodeGen_PECL_Element::cCodeEditorSettings(); $this->addPackageFile('header', $filename); return $this->obToFile($filename); } // }}} // {{{ internal functions /** * Create code for the internal functions like MINIT etc ... * * @access private * @return string code snippet */ function internalFunctionsC() { $need_block = false; $code = " /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION({$this->name}) { "; if (count($this->globals)) { $code .= " ZEND_INIT_MODULE_GLOBALS({$this->name}, php_{$this->name}_init_globals, php_{$this->name}_shutdown_globals)\n"; $need_block = true; } if (count($this->phpini)) { $code .= " REGISTER_INI_ENTRIES();\n"; $need_block = true; } foreach ($this->logos as $logo) { $code .= CodeGen_Tools_Indent::indent(4, $logo->minitCode()); $need_block = true; } if (count($this->constants)) { foreach ($this->constants as $constant) { $code .= CodeGen_Tools_Indent::indent(4, $constant->cCode($this->name)); } $need_block = true; } if (count($this->resources)) { foreach ($this->resources as $resource) { $code .= CodeGen_Tools_Indent::indent(4, $resource->minitCode()); } $need_block = true; } if (count($this->classes)) { foreach ($this->classes as $class) { $code .= CodeGen_Tools_Indent::indent(4, $class->minitCode($this)); } $need_block = true; } if (count($this->streams)) { foreach ($this->streams as $stream) { $code .= CodeGen_Tools_Indent::indent(4, $stream->minitCode($this)); } $need_block = true; } if (isset($this->internalFunctions['MINIT'])) { if ($need_block) $code .= "\n {\n"; $code .= CodeGen_Tools_Indent::indent(8, $this->internalFunctions['MINIT']->code); if ($need_block) $code .= "\n }\n"; } else { $code .="\n /* add your stuff here */\n"; } $code .= " return SUCCESS; } /* }}} */ "; $code .= " /* {{{ PHP_MSHUTDOWN_FUNCTION */ PHP_MSHUTDOWN_FUNCTION({$this->name}) { "; if (count($this->phpini)) { $code .= " UNREGISTER_INI_ENTRIES();\n"; } foreach ($this->logos as $logo) { $code .= CodeGen_Tools_Indent::indent(4, $logo->mshutdownCode()); $need_block = true; } if (isset($this->internalFunctions['MSHUTDOWN'])) { if (count($this->phpini)) $code .= "\n {\n"; $code .= CodeGen_Tools_Indent::indent(4, $this->internalFunctions['MSHUTDOWN']->code); if (count($this->phpini)) $code .= "\n }\n"; } else { $code .="\n /* add your stuff here */\n"; } $code .= " return SUCCESS; } /* }}} */ "; $code .= " /* {{{ PHP_RINIT_FUNCTION */ PHP_RINIT_FUNCTION({$this->name}) { "; if (isset($this->internalFunctions['RINIT'])) { $code .= CodeGen_Tools_Indent::indent(4, $this->internalFunctions['RINIT']->code); } else { $code .= " /* add your stuff here */\n"; } $code .= " return SUCCESS; } /* }}} */ "; $code .= " /* {{{ PHP_RSHUTDOWN_FUNCTION */ PHP_RSHUTDOWN_FUNCTION({$this->name}) { "; if (isset($this->internalFunctions['RSHUTDOWN'])) { $code .= CodeGen_Tools_Indent::indent(4, $this->internalFunctions['RSHUTDOWN']->code); } else { $code .= " /* add your stuff here */\n"; } $code .= " return SUCCESS; } /* }}} */ "; $code .= " /* {{{ PHP_MINFO_FUNCTION */ PHP_MINFO_FUNCTION({$this->name}) { php_info_print_box_start(0); "; foreach ($this->logos as $logo) { $code.= " php_printf(\"<img src='\"); if (SG(request_info).request_uri) { php_printf(\"%s\", (SG(request_info).request_uri)); } php_printf(\"?=%s\", ".($logo->id)."); php_printf(\"' align='right' alt='image' border='0'>\\n\"); "; } if (isset($this->summary)) { $code .= " php_printf(\"<p>".str_replace('"','\\"',$this->summary)."</p>\\n\");\n"; } if (isset($this->release)) { $code .= " php_printf(\"<p>Version {$this->release->version}{$this->release->state} ({$this->release->date})</p>\\n\");\n"; } if (count($this->authors)) { $code .= " php_printf(\"<p><b>Authors:</b></p>\\n\");\n"; foreach ($this->authors as $author) { $code.= CodeGen_Tools_Indent::indent(4, $author->phpinfo()); } } $code.= " php_info_print_box_end(); "; if (isset($this->internalFunctions['MINFO'])) { $code .= "\n {\n"; $code .= $this->internalFunctions['MINFO']->code; $code .= "\n }\n"; } else { $code .= " /* add your stuff here */\n"; } if (count($this->phpini)) { $code .= "\n DISPLAY_INI_ENTRIES();"; } $code .= " } /* }}} */ "; return $code; } // }}} // {{{ public functions /** * Create code for the exported PHP functions * * @access private * @return string code snippet */ function publicFunctionsC() { $code = ""; foreach ($this->functions as $function) { $code .= $function->cCode(&$this); } return $code; } // }}} // {{{ code file /** * Write the complete C code file * * @access private * @param string directory to write to */ function writeCodeFile() { $filename = "{$this->name}.{$this->language}"; // todo extension logic $upname = strtoupper($this->name); ob_start(); echo $this->getLicense(); echo "#include \"php_{$this->name}.h\"\n\n"; echo "#if HAVE_$upname\n\n"; if (isset($this->code["code"]["top"])) { foreach ($this->code["code"]["top"] as $code) { echo CodeGen_Tools_Indent::indent(0, $code); } } foreach ($this->logos as $logo) { echo $logo->cCode($this->name); } if (!empty($this->resources)) { foreach ($this->resources as $resource) { echo $resource->cCode($this); } } echo $this->generateClassRegistrations(); echo $this->generateFunctionRegistrations(); echo $this->generateExtensionEntry(); echo $this->generateGlobalsC(); echo $this->internalFunctionsC(); echo $this->publicFunctionsC(); if (isset($this->code["code"]["bottom"])) { foreach ($this->code["code"]["bottom"] as $code) { echo CodeGen_Tools_Indent::indent(0, $code); } } echo "#endif /* HAVE_$upname */\n\n"; echo CodeGen_PECL_Element::cCodeEditorSettings(); $this->addPackageFile('code', $filename); return $this->obToFile($filename, $this->OB_TABIFY); } // }}} // {{{ config.m4 file /** * Write config.m4 file for autoconf * * @access private * @param string directory to write to */ function writeConfigM4() { $upname = strtoupper($this->name); $flagVar = ($this->language === "cpp") ? "CXXFLAGS" : "CFLAGS"; ob_start(); echo 'dnl dnl $ Id: $ dnl '; if (isset($this->with[$this->name])) { $with = $this->with[$this->name]; echo " PHP_ARG_WITH({$with->name}, whether to enable {$with->name} functions, [ --with-{$with->name}[=DIR] With {$with->name} support]) \n"; } else { echo " PHP_ARG_ENABLE({$this->name}, whether to enable {$this->name} functions, [ --enable-{$this->name} Enable {$this->name} support]) "; } echo "\n"; echo "if test \"\$PHP_$upname\" != \"no\"; then\n"; foreach ($this->configfragments['top'] as $fragment) { echo "$fragment\n"; } foreach ($this->with as $with) { if ($with->name != $this->name) { echo " PHP_ARG_WITH({$with->name}, {$with->summary}, [ --with-{$with->name}[=DIR] With {$with->name} support]) \n"; } $withUpname = strtoupper($with->name); echo " if test -r \"\$PHP_$withUpname/{$with->testfile}\"; then PHP_{$withUpname}_DIR=\"\$PHP_$withUpname\" else AC_MSG_CHECKING(for {$with->name} in default path) for i in ".str_replace(":"," ",$with->defaults)."; do if test -r \"\$i/{$with->testfile}\"; then PHP_{$withUpname}_DIR=\$i AC_MSG_RESULT(found in \$i) break fi done if test \"x\" = \"x\$PHP_{$withUpname}_DIR\"; then AC_MSG_ERROR(not found) fi fi "; $pathes = array(); foreach($with->headers as $header) { $pathes[$header->getPath()] = true; // TODO WTF??? } foreach (array_keys($pathes) as $path) { echo " PHP_ADD_INCLUDE(\$PHP_{$withUpname}_DIR/$path)\n"; } echo " export OLD_$flagVar=\"\$$flagVar\"\n"; echo " export $flagVar=\"\$$flagVar \$INCLUDES -DHAVE_$withUpname\"\n"; foreach($with->headers as $header) { echo $header->configm4($this->name, $this->name); } foreach ($with->libs as $lib) { echo $lib->configm4($this->name, $with->name); } echo " export $flagVar=\"\$OLD_$flagVar\"\n"; } $pathes = array(); foreach($this->headers as $header) { $pathes[$header->getPath()] = true; // TODO WTF??? } foreach (array_keys($pathes) as $path) { echo " PHP_ADD_INCLUDE(\$PHP_{$upname}_DIR/$path)\n"; } if ($this->language === "cpp") { echo " PHP_REQUIRE_CXX\n"; echo " AC_LANG_CPLUSPLUS\n"; echo " PHP_ADD_LIBRARY(stdc++,,{$upname}_SHARED_LIBADD)\n"; } echo " export OLD_$flagVar=\"\$$flagVar\"\n"; echo " export $flagVar=\"\$$flagVar \$INCLUDES -DHAVE_".strtoupper($this->name)."\"\n"; foreach($this->headers as $header) { echo $header->configm4($this->name, $this->name); } foreach ($this->resources as $resource) { echo " AC_CHECK_TYPE({$resource->payload}, [], [AC_MSG_ERROR(required payload type for resource {$resource->name} not found)], [#include \"php_{$this->name}.h\"])\n"; } echo " export $flagVar=\"\$OLD_$flagVar\"\n"; if (count($this->libs)) { $first = true; foreach ($this->libs as $lib) { echo $lib->configm4($this->name, $this->name); } } echo "\n"; echo " PHP_SUBST({$upname}_SHARED_LIBADD) AC_DEFINE(HAVE_$upname, 1, [ ]) PHP_NEW_EXTENSION({$this->name}, ".join(" ", array_keys($this->packageFiles['code']))." , \$ext_shared) "; if (count($this->makefragment)) { echo " PHP_ADD_MAKEFILE_FRAGMENT\n"; $frag = fopen($this->dirpath."/Makefile.frag","w"); foreach($this->makefragment as $block) { fputs($frag, CodeGen_Tools_Indent::tabify("\n$block\n")); } fclose($frag); } foreach ($this->configfragments['bottom'] as $fragment) { echo "$fragment\n"; } echo " fi "; $this->addPackageFile("conf", "config.m4"); return $this->obToFile("config.m4", $this->OB_TABIFY); } // }}} // {{{ config.w32 file /** * Write config.w32 file for new windows build system * * @access private * @param string directory to write to */ function writeConfigW32() { // TODO fragments $upname = strtoupper($this->name); ob_start(); echo '// $ Id: $ // vim:ft=javascript '; if (isset($this->with[$this->name])) { echo " ARG_WITH('{$this->name}', '{$this->summary}', 'no'); "; } else { echo " ARG_ENABLE('{$this->name}' , '{$this->summary}', 'no'); "; } echo "if (PHP_$upname == \"yes\") {\n"; // add libraries from <deps> section foreach ($this->libs as $lib) { echo $lib->configw32($this->name, $this->name); } foreach($this->headers as $header) { echo $header->configw32($this->name, $this->name); } echo " EXTENSION(\"{$this->name}\", \"".join(" ", array_keys($this->packageFiles['code']))."\");\n"; echo " AC_DEFINE(\"HAVE_$upname\", 1, \"{$this->name} support\");\n"; echo "}\n"; $this->addPackageFile("conf", "config.w32"); return $this->obToFile("config.w32", $this->OB_UNTABIFY | $this->OB_DOSIFY); } // }}} // {{{ M$ dev studio project file /** * Write project file for VisualStudio V6 * * @access private * @param string directory to write to */ function writeMsDevStudioDsp() { ob_start(); // these system libraries are always needed? // (list taken from sample *.dsp files in php ext tree...) $winlibs = "kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib "; $winlibs.= "shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib"; // add libraries from <deps> section if (count($this->libs)) { foreach ($this->libs as $lib) { if (!$lib["platform"]->test("windows")) { continue; } $winlibs .= " $lib[name].lib"; } } echo '# Microsoft Developer Studio Project File - Name="'.$this->name.'" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG='.$this->name.' - Win32 Debug_TS !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "'.$this->name.'.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "'.$this->name.'.mak" CFG="'.$this->name.' - Win32 Debug_TS" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "'.$this->name.' - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "'.$this->name.' - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "'.$this->name.' - Win32 Release_TS" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release_TS" # PROP BASE Intermediate_Dir "Release_TS" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release_TS" # PROP Intermediate_Dir "Release_TS" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "'.strtoupper($this->name).'_EXPORTS" /YX /FD /c # ADD CPP /nologo /MT /W3 /GX /O2 /I "..\.." /I "..\..\Zend" /I "..\..\TSRM" /I "..\..\main" /D "WIN32" /D "PHP_EXPORTS" /D "COMPILE_DL_'.strtoupper($this->name).'" /D ZTS=1 /D HAVE_'.strtoupper($this->name).'=1 /D ZEND_DEBUG=0 /D "NDEBUG" /D "_WINDOWS" /D "ZEND_WIN32" /D "PHP_WIN32" /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x407 /d "NDEBUG" # ADD RSC /l 0x407 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 '.$winlibs.' /nologo /dll /machine:I386 # ADD LINK32 php4ts.lib '.$winlibs.' /nologo /dll /machine:I386 /out:"..\..\Release_TS\php_'.$this->name.'.dll" /libpath:"..\..\Release_TS" /libpath:"..\..\Release_TS_Inline" !ELSEIF "$(CFG)" == "'.$this->name.' - Win32 Debug_TS" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug_TS" # PROP BASE Intermediate_Dir "Debug_TS" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug_TS" # PROP Intermediate_Dir "Debug_TS" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "'.strtoupper($this->name).'_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\Zend" /I "..\..\TSRM" /I "..\..\main" /D ZEND_DEBUG=1 /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "PHP_EXPORTS" /D "COMPILE_DL_'.strtoupper($this->name).'" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_'.strtoupper($this->name).'=1 /YX /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x407 /d "_DEBUG" # ADD RSC /l 0x407 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 '.$winlibs.' /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 php4ts_debug.lib '.$winlibs.' /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS\php_'.$this->name.'.dll" /pdbtype:sept /libpath:"..\..\Debug_TS" !ENDIF # Begin Target # Name "'.$this->name.' - Win32 Release_TS" # Name "'.$this->name.' - Win32 Debug_TS" '; echo ' # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" '; foreach ($this->packageFiles['code'] as $basename => $filepath) { $filename = "./$basename"; echo " # Begin Source File SOURCE=$filename # End Source File "; } echo ' # End Group '; echo ' # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" '; foreach ($this->packageFiles['header'] as $filename) { if ($filename{0}!='/' && $filename{0}!='.') { $filename = "./$filename"; } $filename = str_replace("/","\\",$filename); echo " # Begin Source File SOURCE=$filename # End Source File "; } echo '# End Group # End Target # End Project '; $filename = $this->name.".dsp"; $this->addPackageFile("conf", $filename); return $this->obToFile($filename, $this->OB_UNTABIFY | $this->OB_DOSIFY); } // }}} /** * Write authors to the CREDITS file * * @access private * @param string directory to write to */ function writeCredits() { if (count($this->authors)) { $this->addPackageFile("doc", "CREDITS"); $fp = fopen($this->dirpath."/CREDITS", "w"); fputs($fp, "{$this->name}\n"); $names = array(); foreach($this->authors as $author) { $names[] = $author->name; } fputs($fp, join(", ", $names) . "\n"); fclose($fp); } } /** * Write EXPERIMENTAL file for non-stable extensions * * @access private * @param string directory to write to */ function writeExperimental() { if (($this->release) && isset($this->release->state) && $this->release->state !== 'stable') { $this->addPackageFile("doc", "EXPERIMENTAL"); $fp = fopen($this->dirpath."/EXPERIMENTAL", "w"); fputs($fp, "this extension is experimental, its functions may change their names or move to extension all together so do not rely to much on them you have been warned! "); fclose($fp); } } /** * Write PEAR/PECL package.xml file * * @access private * @param string directory to write to */ function writePackageXml() { ob_start(); echo "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?> <!DOCTYPE package SYSTEM \"http://pear.php.net/dtd/package-1.0\"> <package> <name>{$this->name}</name> "; if (isset($this->summary)) { echo " <summary>{$this->summary}</summary>\n"; } if (isset($this->description)) { echo " <description>\n".rtrim($this->description)."\n </description>\n"; } if ($this->license) { echo " <license>".$this->license->shortname."</license>\n"; } foreach ($this->with as $with) { $configOption = "--with-".$with->name; echo " <configureoptions>\n"; echo " <configureoption name=\"{$configOption}\" default=\"autodetect\" prompt=\"{$with->name} installation directory?\" />\n"; echo " </configureoptions>\n"; } if (count($this->authors)) { echo "\n <maintainers>\n"; foreach ($this->authors as $author) { echo $author->packageXml(); } echo " </maintainers>\n"; } if (isset($this->release)) { echo $this->release->packageXml(); } // TODO dependencies echo "\n <filelist>\n"; echo " <dir role=\"doc\" name=\"/\">\n"; if (@is_array($this->packageFiles['doc'])) { foreach ($this->packageFiles['doc'] as $file) { echo " <file role=\"doc\">$file</file>\n"; } } foreach (array("conf", "code", "header") as $type) { foreach ($this->packageFiles[$type] as $basename => $filepath) { echo " <file role=\"src\">$basename</file>\n"; } } echo " </dir>\n"; echo " </filelist>\n"; echo "</package>\n"; return $this->obToFile("package.xml"); } // }}} /** * add a custom test case * * @access public * @param object a Test object */ function addTest($test) { if (! is_a($test, "CodeGen_PECL_Element_Test")) { return PEAR::raiseError("Parameter is not a CodeGen_PECL Test instance"); } $this->testcases[$test->name] = $test; return true; } /** * Write test case files * * @access private */ function writeTestFiles() { @mkdir($this->dirpath."/tests"); // function related tests foreach ($this->functions as $function) { $function->writeTest($this); } // custom test cases (may overwrite custom function test cases) foreach ($this->testcases as $test) { $test->writeTest($this); } } /** * Write .cvsignore entries * * @access public * @param string directory to write to */ function writeDotCvsignore() { // open output file $fp = fopen($this->dirpath."/.cvsignore", "w"); // unix specific entries if ($this->platform->test("unix")) { fputs($fp, "*.lo\n"); fputs($fp, "*.la\n"); fputs($fp, ".deps\n"); fputs($fp, ".libs\n"); fputs($fp, "Makefile\n"); fputs($fp, "Makefile.fragments\n"); fputs($fp, "Makefile.global\n"); fputs($fp, "Makefile.objects\n"); fputs($fp, "acinclude.m4\n"); fputs($fp, "aclocal.m4\n"); fputs($fp, "autom4te.cache\n"); fputs($fp, "build\n"); fputs($fp, "config.cache\n"); fputs($fp, "config.guess\n"); fputs($fp, "config.h\n"); fputs($fp, "config.h.in\n"); fputs($fp, "config.log\n"); fputs($fp, "config.nice\n"); fputs($fp, "config.status\n"); fputs($fp, "config.sub\n"); fputs($fp, "configure\n"); fputs($fp, "configure.in\n"); fputs($fp, "conftest\n"); fputs($fp, "conftest.c\n"); fputs($fp, "include\n"); fputs($fp, "install-sh\n"); fputs($fp, "libtool\n"); fputs($fp, "ltmain.sh\n"); fputs($fp, "missing\n"); fputs($fp, "mkinstalldirs\n"); fputs($fp, "modules\n"); fputs($fp, "scan_makefile_in.awk\n"); } // windows specific entries if ($this->platform->test("windows")) { fputs($fp, "*.dsw\n"); fputs($fp, "*.plg\n"); fputs($fp, "*.opt\n"); fputs($fp, "*.ncb\n"); fputs($fp, "Release\n"); fputs($fp, "Release_inline\n"); fputs($fp, "Debug\n"); fputs($fp, "Release_TS\n"); fputs($fp, "Release_TSDbg\n"); fputs($fp, "Release_TS_inline\n"); fputs($fp, "Debug_TS\n"); } // "pear package" creates .tgz fputs($fp, "*.tgz\n"); // some typical backup file patterns fputs($fp, "*~\n"); fputs($fp, "#*#\n"); fputs($fp, ".#*\n"); fclose($fp); } /** * Describe next steps after successfull extension creation * * @access private * @param string directory where extension was build */ function successMsg() { $msg = "Your extension has been created in directory {$this->dirpath}.\n"; if (!isset($this->readme)) { $msg.= "See ".basename($this->dirpath)."/README for further instructions.\n"; } return $msg; } /** * Generate README file (custom or default) * * @access private * @param string directory to write to */ function writeReadme() { $configOption = isset($this->with[$this->name]) ? "--with-" : "--enable-"; $configOption.= $this->name; ob_start(); ?> This is a standalone PHP extension created using CodeGen_PECL <?php echo self::version(); ?> HACKING ======= There are two ways to modify an extension created using CodeGen_PECL: 1) you can modify the generated code as with any other PHP extension 2) you can add custom code to the CodeGen_PECL XML source and re-run pecl-gen The 2nd approach may look a bit complicated but you have be aware that any manual changes to the generated code will be lost if you ever change the XML specs and re-run PECL-Gen. All changes done before have to be applied to the newly generated code again. Adding code snippets to the XML source itself on the other hand may be a bit more complicated but this way your custom code will always be in the generated code no matter how often you rerun CodeGen_PECL. <?php if ($this->platform->test("unix")): ?> BUILDING ON UNIX etc. ===================== To compile your new extension, you will have to execute the following steps: 1. $ ./phpize 2. $ ./configure [<?php echo $configOption; ?>] 3. $ make [4. $ make test ] # NOTE: this doesn't work right now *) 5. $ [sudo] make install *) this is a general problem with "make test" and standalone extensions (that is being worked on) so please don't blame CodeGen_PECL for this <?php endif; ?> <?php if ($this->platform->test("windows")): ?> BUILDING ON WINDOWS =================== The extension provides the VisualStudio V6 project file <?php echo $this->name.".dsp" ?> To compile the extension you open this file using VisualStudio, select the apropriate configuration for your installation (either "Release_TS" or "Debug_TS") and create "php_<?php echo $this->name; ?>.dll" After successfull compilation you have to copy the newly created "php_<?php echo $this->name; ?>.dll" to the PHP extension directory (default: C:\PHP\extensions). <?php endif; ?> TESTING ======= You can now load the extension using a php.ini directive extension="php_<?php echo $this->name; ?>.[so|dll]" or load it at runtime using the dl() function dl("php_<?php echo $this->name; ?>.[so|dll]"); The extension should now be available, you can test this using the extension_loaded() function: if (extension_loaded(<?php echo $this->name; ?>)) echo "<?php echo $this->name; ?> loaded :)"; else echo "something is wrong :("; The extension will also add its own block to the output of phpinfo(); <?php return $this->obToFile("README"); } var $OB_DOSIFY = 1; var $OB_TABIFY = 2; var $OB_UNTABIFY = 4; /** * write current output buffer to file * * @param file path * @param formating flags * @access private */ function obToFile($path, $flags = 0) { $fp = fopen($this->dirpath . "/" . $path, "w"); if (!is_resource($fp)) { return PEAR::raiseError("can't write to output file '$path"); } $text = ob_get_clean(); if ($flags && $this->OB_TABIFY) { $text = CodeGen_Tools_Indent::tabify($text); } else if ($flags && $this->OB_UNTABIFY) { $text = CodeGen_Tools_Indent::untabify($text); } if ($flags && $this->OB_DOSIFY) { $text = CodeGen_Tools_Indent::tabify($text); } fputs($fp, $text); fclose($fp); return true; } } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * indent-tabs-mode:nil * End: */ ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/ExtensionParser.php?r=1.1&p=1 Index: pear/CodeGen_PECL/ExtensionParser.php +++ pear/CodeGen_PECL/ExtensionParser.php <?php /** * Extension to the generic parser that adds PECL specific tags * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: ExtensionParser.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ /** * includes */ require_once "CodeGen/ExtensionParser.php"; require_once "CodeGen/PECL/Maintainer.php"; /** * Extension to the generic parser that adds PECL specific tags * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_ExtensionParser extends CodeGen_ExtensionParser { function tagstart_extension_maintainer($attr) { // check: never popped? $this->pushHelper(new CodeGen_PECL_Maintainer); return true; } function tagstart_extension_release($attr) { $this->pushHelper(new CodeGen_PECL_Release); return true; } function tagstart_extension_function($attr) { $this->pushHelper(new CodeGen_PECL_Element_Function); $role = isset($attr["role"]) ? $attr["role"] : "public"; if (isset($attr["name"])) { if ($role == "public" && $this->extension->prefix) { $err = $this->helper->setName($this->extension->prefix."_".$attr["name"]); } else { $err = $this->helper->setName($attr["name"]); } if (PEAR::isError($err)) { return $err; } } else { return PEAR::raiseError("'name' attribut for <function> missing"); } $err = $this->helper->setRole($role); if (PEAR::isError($err)) { return $err; } return true; } function tagstart_extension_functions_function($attr) { return $this->tagstart_extension_function($attr); } function tagstart_extension_class_function($attr) { // TODO modify $this->pushHelper(new CodeGen_PECL_Element_Method($this->helper->getName())); if (isset($attr["name"])) { $err = $this->helper->setName($attr["name"]); if (PEAR::isError($err)) { return $err; } } else { return PEAR::raiseError("'name' attribut for <function> missing"); } return true; } function tagend_extension_function_summary($attr, $data) { return $this->helper->setSummary(trim($data)); } function tagstart_extension_function_description($attr) { $this->verbatim(); } function tagend_extension_function_description($attr, $data) { return $this->helper->setDescription(CodeGen_Tools_Indent::linetrim($data)); } function tagend_extension_function_proto($attr, $data) { return $this->helper->setProto(trim($data), $this->extension); } function tagstart_extension_function_code($attr) { if (isset($attr["src"])) { if (!file_exists($attr["src"])) { return PEAR::raiseError("'src' file '$attr[src]' not found in <code>"); } if (!is_readable($attr["src"])) { return PEAR::raiseError("Cannot read 'src' file '$attr[src]' in <code>"); } } } function tagend_extension_function_code($attr, $data, $line=0, $file="") { if (isset($attr["src"])) { return $this->helper->setCode(CodeGen_Tools_Indent::linetrim(file_get_contents($attr["src"]))); } else { return $this->helper->setCode($data, $line, $file); } } function tagend_extension_function($attr, $data) { $err = $this->extension->addFunction($this->helper); $this->popHelper(); return $err; } function tagend_extension_functions_function($attr, $data) { return $this->tagend_extension_function($attr, $data); } function tagend_extension_functions_function_code($attr, $data) { return $this->tagend_extension_function_code($attr, $data); } function tagend_extension_functions_function_summary($attr, $data) { return $this->tagend_extension_function_summary($attr, $data); } function tagend_extension_functions_function_description($attr, $data) { return $this->tagend_extension_function_description($attr, $data); } function tagend_extension_functions_function_proto($attr, $data) { return $this->tagend_extension_function_proto($attr, $data); } function tagend_class_function($attr, $data) { $err = $this->helper_prev->addMethod($this->helper); $this->popHelper(); return $err; } function tagend_functions($attr, $data) { return true; } function tagstart_extension_resource($attr) { return $this->tagstart_resources_resource($attr); } function tagstart_resources_resource($attr) { $this->pushHelper(new CodeGen_PECL_Element_Resource); if (isset($attr["name"])) { $err = $this->helper->setName($attr["name"]); if (PEAR::isError($err)) { return $err; } } else { return PEAR::raiseError("name attribut for resource missing"); } if (isset($attr["payload"])) { $err = $this->helper->setPayload($attr["payload"]); if (PEAR::isError($err)) { return $err; } } else { return PEAR::raiseError("payload attribut for resource missing"); } if (isset($attr["alloc"])) { $err = $this->helper->setAlloc($attr["alloc"]); if (PEAR::isError($err)) { return $err; } } return true; } function tagend_resource_destruct($attr, $data) { return $this->helper->setDestruct(CodeGen_Tools_Indent::linetrim($data)); } function tagend_resource_description($attr, $data) { return $this->helper->setDescription(CodeGen_Tools_Indent::linetrim($data)); } function tagend_extension_resource($attr, $data) { return $this->tagend_resources_resource($attr, $data); } function tagend_resources_resource($attr, $data) { $err = $this->extension->addResource($this->helper); $this->popHelper(); return $err; } function tagend_resources($attr, $data) { return true; } function tagend_extension_logo($attr, $data) { // TODO checks if (!isset($attr["name"])) { $attr["name"] = $this->extension->name; } $logo = new CodeGen_PECL_Element_Logo($attr["name"]); if (!isset($attr["mimetype"])) { $attr["mimetype"] = false; } if (isset($attr["src"])) { $err = $logo->loadFile($attr["src"], $attr["mimetype"]); if (PEAR::isError($err)) { return $err; } } else { // we support uuencoded and base64 encoded embedded data $decoded = base64_decode($data); if (!is_string($decoded)) { PEAR::raiseError("only uuencoded and base64 encoded image data is supported for embedded data"); } $err = $logo->setData($decoded, $attr["mimetype"]); if (PEAR::isError($err)) { return $err; } } return $this->extension->addLogo($logo); } function tagend_extension_constant($attr, $data) { return $this->tagend_constants_constant($attr, $data); } function tagend_constants_constant($attr, $data) { $const = new CodeGen_PECL_Element_Constant; if (isset($attr["name"])) { $err = $const->setName($attr["name"]); if (PEAR::isError($err)) { return $err; } } else { return PEAR::raiseError("name attribut for constant missing"); } if (isset($attr["type"])) { $err = $const->setType($attr["type"]); } else { $err = $const->setType("int"); // default } if (PEAR::isError($err)) { return $err; } if (isset($attr["value"])) { $err = $const->setValue($attr["value"]); } else { $const->setDefine(false); $err = $const->setValue($attr["name"]); // default -> mimic a C #define or enum value } if (PEAR::isError($err)) { return $err; } if (isset($attr["define"])) { $err = $const->setDefine($attr["define"]); } if (PEAR::isError($err)) { return $err; } $const->setDesc(CodeGen_Tools_Indent::linetrim($data)); return $this->extension->addConstant($const); } function tagend_constants($attr, $data) { return true; } function tagend_extension_global($attr, $data) { return $this->tagend_globals_global($attr, $data); } function tagend_globals_global($attr, $data) { $global = new CodeGen_PECL_Element_Global; if (isset($attr["name"])) { $err = $global->setName($attr["name"]); if (PEAR::isError($err)) { return $err; } } else { return PEAR::raiseError("name attribut for global missing"); } if (isset($attr["type"])) { $err = $global->setType($attr["type"]); if (PEAR::isError($err)) { return $err; } } else { return PEAR::raiseError("type attribut for global missing"); } if (isset($attr["value"])) { $err = $global->setValue($attr["value"]); if (PEAR::isError($err)) { return $err; } } return $this->extension->addGlobal($global); } function tagend_extension_phpini($attr, $data) { return $this->tagend_globals_phpini($attr, $data); } function tagend_globals_phpini($attr, $data) { $ini = new CodeGen_PECL_Element_Ini; if (isset($attr["name"])) { $err = $ini->setName($attr["name"]); if (PEAR::isError($err)) { return $err; } } else { return PEAR::raiseError("name attribut for php.ini directive missing"); } if (isset($attr["type"])) { $err = $ini->setType($attr["type"]); if (PEAR::isError($err)) { return $err; } } if (isset($attr["value"])) { $err = $ini->setValue($attr["value"]); if (PEAR::isError($err)) { return $err; } } if (isset($attr["access"])) { $err = $ini->setAccess($attr["access"]); if (PEAR::isError($err)) { return $err; } } if (isset($attr["onupdate"])) { $err = $ini->setOnUpdate($attr["onupdate"]); if (PEAR::isError($err)) { return $err; } } $ini->setDesc(CodeGen_Tools_Indent::linetrim($data)); $err = $this->extension->addPhpini($ini); if (PEAR::isError($err)) { return $err; } // php.ini settings are stored in modul-global variables $global = new CodeGen_PECL_Element_Global; $err = $global->setName($ini->name); if (PEAR::isError($err)) { return $err; } $err = $global->setType($ini->c_type); if (PEAR::isError($err)) { return $err; } $err = $global->setValue($ini->value); if (PEAR::isError($err)) { return $err; } $err = $this->extension->addGlobal($global); return $err; } function tagend_globals($attr, $data) { return true; } function tagstart_extension_deps($attr) { if (isset($attr["language"])) { $err = $this->extension->setLanguage($attr["language"]); if (PEAR::isError($err)) { return $err; } } if (isset($attr["platform"])) { $err = $this->extension->setPlatform($attr["platform"]); if (PEAR::isError($err)) { return $err; } } } function tagstart_extension_deps_lib($attr) { if (!isset($attr["name"])) { return PEAR::raiseError(""); } if (!isset($attr["platform"])) { $attr["platform"] = "all"; } $lib = new CodeGen_PECL_Dependency_Lib($attr["name"], $attr["platform"]); if (isset($attr['path'])) { $lib->setPath($attr['path']); } if (isset($attr['function'])) { $lib->setFunction($attr['function']); } $this->extension->addLib($lib); return true; } function tagstart_extension_deps_header($attr) { // TODO check name $header = new CodeGen_PECL_Dependency_Header($attr["name"]); if (isset($attr['path'])) { $header->setPath($attr["path"]); } if (isset($attr['prepend'])) { $header->setPrepend($attr["prepend"]); } $this->extension->addHeader($header); } function tagstart_extension_deps_with($attr) { $with = new CodeGen_PECL_Dependency_With; if (!isset($attr['name'])) { $attr["name"] = $this->extension->name; } $err = $with->setName($attr["name"]); if (PEAR::isError($err)) { return $err; } if (isset($attr["testfile"])) { $with->setTestfile($attr["testfile"]); } if (isset($attr["defaults"])) { $with->setDefaults($attr["defaults"]); } $this->pushHelper($with); return true; } function tagstart_deps_with_header($attr) { // TODO check name $header = new CodeGen_PECL_Dependency_Header($attr["name"]); if (isset($attr['path'])) { $header->setPath($attr["path"]); } if (isset($attr['prepend'])) { $header->setPrepend($attr["prepend"]); } $this->helper->addHeader($header); } function tagstart_deps_with_lib($attr) { if (!isset($attr["platform"])) { $attr["platform"] = "all"; } $lib = new CodeGen_PECL_Dependency_Lib($attr["name"], $attr["platform"]); if (isset($attr['path'])) { $lib->setPath($attr['path']); } if (isset($attr['function'])) { $lib->setFunction($attr['function']); } $this->helper->addLib($lib); } function tagend_extension_deps_with($attr, $data) { $this->helper->setSummary($data); $this->extension->addWith($this->helper); $this->popHelper(); } function tagstart_extension_deps_file($attr) { if (!isset($attr['name'])) { return PEAR::raiseError("name attribut for file missing"); } return $this->extension->addSourceFile($attr['name']); } function tagstart_extension_code($attr) { if (isset($attr["src"])) { if (!file_exists($attr["src"])) { return PEAR::raiseError("Soruce file '$attr[src]' not found"); } if (!is_readable($attr["src"])) { return PEAR::raiseError("Cannot read source file '$attr[src]'"); } } } function tagend_extension_code($attr, $data) { $role = isset($attr["role"]) ? $attr["role"] : "code"; $position = isset($attr["position"]) ? $attr["position"] : "bottom"; if (isset($attr["src"])) { return $this->extension->addCode($role, $position, CodeGen_Tools_Indent::linetrim(file_get_contents($attr["src"]))); } else { return $this->extension->addCode($role, $position, CodeGen_Tools_Indent::linetrim($data)); } } function tagend_extension_makefile($attr, $data) { return $this->extension->addMakeFragment(CodeGen_Tools_Indent::linetrim($data)); } function tagend_extension_deps_configm4($attr, $data) { return $this->extension->addConfigFragment(CodeGen_Tools_Indent::linetrim($data), isset($attr['position']) ? $attr['position'] : "top"); } function tagstart_test($attr) { $test = new CodeGen_PECL_Element_Test(); if (isset($attr["name"])) { $err = $test->setName($attr["name"]); if (PEAR::isError($err)) { return $err; } } else { return PEAR::raiseError("name attribut for class missing"); } $this->pushHelper($test); } function tagend_test_title($attr, $data) { $this->helper->setTitle(CodeGen_Tools_Indent::linetrim($data)); } function tagend_test_skipif($attr, $data) { $this->helper->setSkipIf(CodeGen_Tools_Indent::linetrim($data)); } function tagend_test_get($attr, $data) { $this->helper->setGet(CodeGen_Tools_Indent::linetrim($data)); } function tagend_test_post($attr, $data) { $this->helper->setPost(CodeGen_Tools_Indent::linetrim($data)); } function tagstart_test_code($attr) { if (isset($attr["src"])) { if (!file_exists($attr["src"])) { return PEAR::raiseError("Soruce file '$attr[src]' not found"); } if (!is_readable($attr["src"])) { return PEAR::raiseError("Cannot read source file '$attr[src]'"); } } } function tagend_test_code($attr, $data) { if (isset($attr["src"])) { $this->helper->setCode(CodeGen_Tools_Indent::linetrim(file_get_contents($attr["src"]))); } else { $this->helper->setCode(CodeGen_Tools_Indent::linetrim($data)); } } function tagend_test_output($attr, $data) { $this->helper->setOutput(CodeGen_Tools_Indent::linetrim($data)); } function tagend_test($attr, $data) { $err = $this->extension->addTest($this->helper); $this->popHelper(); return $err; } function tagend_tests($attr, $data) { return true; } function tagstart_class($attr) { $this->pushHelper(new CodeGen_PECL_Element_Class); if (isset($attr["name"])) { $err = $this->helper->setName($attr["name"]); if (PEAR::isError($err)) { return $err; } } else { return PEAR::raiseError("name attribut for class missing"); } if (PEAR::isError($err)) { return $err; } return true; } function tagend_class_summary($attr, $data) { return $this->helper->setSummary(trim($data)); } function tagend_class_description($attr, $data) { return $this->helper->setDescription(CodeGen_Tools_Indent::linetrim($data)); } function tagstart_class_code($attr) { if (isset($attr["src"])) { if (!file_exists($attr["src"])) { return PEAR::raiseError("Soruce file '$attr[src]' not found"); } if (!is_readable($attr["src"])) { return PEAR::raiseError("Cannot read source file '$attr[src]'"); } } } function tagend_class_code($attr, $data) { if (isset($attr["src"])) { return $this->helper->setCode(CodeGen_Tools_Indent::linetrim(file_get_contents($attr["src"]))); } else { return $this->helper->setCode(CodeGen_Tools_Indent::linetrim($data)); } } function tagstart_class_property($attr) { if (!isset($attr["name"])) { return PEAR::raiseError("Name attribute missing for property"); } $prop = new CodeGen_PECL_Element_Property; $err = $prop->setName($attr["name"]); if (PEAR::isError($err)) { return $err; } if (isset($attr["type"])) { $err = $prop->setType($attr["type"]); if (PEAR::isError($err)) { return $err; } } if (isset($attr["value"])) { $err = $prop->setValue($attr["value"]); if (PEAR::isError($err)) { return $err; } } return $this->helper->addProperty($prop); } function tagend_class($attr, $data) { $err = $this->extension->addClass($this->helper); $this->popHelper(); return true; } function tagstart_stream($attr) { $this->pushHelper(new CodeGen_PECL_Element_Stream); if (isset($attr["name"])) { $err = $this->helper->setName($attr["name"]); if (PEAR::isError($err)) { return $err; } } else { return PEAR::raiseError("'name' attribut for <stream> missing"); } } function tagend_stream_open($attr, $data) { $this->helper->addCode("open", $data); } function tagend_stream_close($attr, $data) { $this->helper->addCode("close", $data); } function tagend_stream_stat($attr, $data) { $this->helper->addCode("stat", $data); } function tagend_stream_urlstat($attr, $data) { $this->helper->addCode("urlstat", $data); } function tagend_stream_diropen($attr, $data) { $this->helper->addCode("diropen", $data); } function tagend_stream_unlink($attr, $data) { $this->helper->addCode("unlink", $data); } function tagend_stream_rename($attr, $data) { $this->helper->addCode("rename", $data); } function tagend_stream_mkdir($attr, $data) { $this->helper->addCode("mkdir", $data); } function tagend_stream_rmdir($attr, $data) { $this->helper->addCode("rmdir", $data); } function tagend_stream_summary($attr, $data) { $this->helper->addCode("summary", $data); } function tagend_stream_write($attr, $data) { $this->helper->addCode("write", $data); } function tagend_stream_read($attr, $data) { $this->helper->addCode("read", $data); } function tagend_stream_flush($attr, $data) { $this->helper->addCode("flush", $data); } function tagend_stream_seek($attr, $data) { $this->helper->addCode("seek", $data); } function tagend_stream_cast($attr, $data) { $this->helper->addCode("cast", $data); } function tagend_stream_set($attr, $data) { $this->helper->addCode("set", $data); } function tagend_stream($attr, $data) { $this->extension->addStream($this->helper); $this->popHelper(); } } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * indent-tabs-mode:nil * End: */ ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/LICENSE.txt?r=1.1&p=1 Index: pear/CodeGen_PECL/LICENSE.txt +++ pear/CodeGen_PECL/LICENSE.txt -------------------------------------------------------------------- The PHP License, Version 3.0 Copyright (c) 1999 - 2003 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 <http://www.php.net/>". 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 <http://www.php.net>. This product includes the Zend Engine, freely available at <http://www.zend.com>. http://cvs.php.net/co.php/pear/CodeGen_PECL/Maintainer.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Maintainer.php +++ pear/CodeGen_PECL/Maintainer.php <?php /** * PECL specific Maintainer extensions * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Maintainer.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ /** * includes */ require_once "CodeGen/Maintainer.php"; /** * PECL specific Maintainer extensions * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Maintainer extends CodeGen_Maintainer { /** * Generate a phpinfo line for this author * * @access public * @return string phpinfo() line */ function phpinfo() { return " php_printf(\"<p>{$this->name} &lt;{$this->email}&gt; ({$this->role})</p>\\n\");\n"; } /** * Generate a package.xml <maintainer> entry for this author * * @access public * @return string phpinfo() line */ function packageXml() { $code = " <maintainer>\n"; $code.= " <user>{$this->user}</user>\n"; $code.= " <name>{$this->name}</name>\n"; $code.= " <email>{$this->email}</email>\n"; $code.= " <role>{$this->role}</role>\n"; $code.= " </maintainer>\n"; return $code; } } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * indent-tabs-mode:nil * End: */ ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/RFC_proto.txt?r=1.1&p=1 Index: pear/CodeGen_PECL/RFC_proto.txt +++ pear/CodeGen_PECL/RFC_proto.txt the grammer for a prototype would look like this: ? proto : type name '(' param-spec ')' name : [A-Za-z_][A-Za-z0-9_]* type : "void" | typespec typespec : typename | typename '&' typename : 'bool' | 'boolean' | 'int' | 'integer' | 'long' | 'float' | 'double' | 'real' | 'string' | 'array' | 'object' | 'object' name | 'resource' | 'resource' name | 'mixed' | 'callback' | 'stream' param-spec: 'void' | '...' | param-list | param-list ',' '...' param-list: parameter | parm-list ',' parameter parameter : typespec name | typespec name '=' default default : "true" | "false" | "array()" | "null" | numeric | string string : '"' character* '"' numeric : ... the usual int, float, hex and octal stuff ... http://cvs.php.net/co.php/pear/CodeGen_PECL/Release.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Release.php +++ pear/CodeGen_PECL/Release.php <?php /** * PECL specific extensions to the Release class * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Release.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ /** * includes */ require_once "CodeGen/Release.php"; /** * PECL specific extensions to the Release class * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Release extends CodeGen_Release { /** * generate XML fragment for package.xml * * @access public * @return string XML fragment */ function packageXml() { $code = "\n <release>\n"; foreach (array("version", "date", "state", "notes") as $key) { if ($this->$key !== "") { $code.= " <$key>{$this->$key}</$key>\n"; } } $code.= " </release>\n"; return $code; } } ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/extension.dtd?r=1.1&p=1 Index: pear/CodeGen_PECL/extension.dtd +++ pear/CodeGen_PECL/extension.dtd <!ELEMENT extension (summary|description|license|maintainers|logo|release|changelog|functions|constants|globals|deps|resources|code|streams|tests|makefile)*> <!ATTLIST extension name CDATA #REQUIRED > <!ELEMENT summary (#PCDATA)> <!ELEMENT description (#PCDATA)> <!ELEMENT maintainers (maintainer)+> <!ELEMENT maintainer (user|role|name|email)*> <!ELEMENT logo (#PCDATA)> <!ATTLIST logo src CDATA #REQUIRED > <!ELEMENT user (#PCDATA)> <!ELEMENT role (#PCDATA)> <!ELEMENT email (#PCDATA)> <!ELEMENT changelog (release)*> <!ELEMENT release (version|license|state|date|notes|filelist|deps)*> <!ELEMENT version (#PCDATA)> <!ELEMENT state (#PCDATA)> <!ELEMENT license (#PCDATA)> <!ELEMENT date (#PCDATA)> <!ELEMENT notes (#PCDATA)> <!ELEMENT functions (function)*> <!ELEMENT function (summary|proto|description|code)*> <!ATTLIST function role (internal|private|public) "public" name CDATA #REQUIRED > <!ELEMENT proto (#PCDATA)> <!ELEMENT code (#PCDATA)> <!ATTLIST code role (header|code) "code" src CDATA > <!ELEMENT constants (constant)*> <!ELEMENT constant (#PCDATA)> <!ATTLIST constant name CDATA #REQUIRED value CDATA #REQUIRED type (string|int|float) "string" > <!ELEMENT globals (phpini|global)*> <!ELEMENT phpini (#PCDATA)> <!ATTLIST phpini name CDATA #REQUIRED type (bool|int|float|string) "string" value CDATA #REQUIRED access (system|perdir|user|all) "all" onupdate CDATA #IMPLIED > <!ELEMENT global (#PCDATA)> <!ATTLIST global name CDATA #REQUIRED type CDATA #REQUIRED value CDATA #IMPLIED > <!ELEMENT deps (with|lib|header|file|program)*> <!ATTLIST deps language (c|cpp) "c" platform (unix|win32|all) "all" > <!ELEMENT with (#PCDATA)> <!ATTLIST with defaults CDATA #REQUIRED testfile CDATA #REQUIRED name CDATA #IMPLIED > <!ELEMENT lib (#PCDATA)> <!ATTLIST lib name CDATA #REQUIRED function CDATA #REQUIRED searchpath CDATA #IMPLIED platform (unix|win32|all) "all" > <!ELEMENT header (#PCDATA)> <!ATTLIST header name CDATA #REQUIRED function CDATA #IMPLIED searchpath CDATA #IMPLIED platform (unix|win32|all) "all" prepend (yes|no) "no" > <!ELEMENT resources (resource)*> <!ELEMENT resource (description?, destruct?)> <!ATTLIST resource name CDATA #REQUIRED payload CDATA #IMPLIED alloc (yes|no) "no" > <!ELEMENT destruct (#PCDATA)> <!ELEMENT streams (stream)*> <!ELEMENT stream (description?, ops?, data?)> <!ATTLIST stream name CDATA #REQUIRED > <!ELEMENT ops (op)*> <!ELEMENT op (#PCDATA)> <!ATTLIST op name CDATA #REQUIRED > <!ELEMENT tests (test)*> <!ELEMENT test (title, skipif?, post?, get?, code, output)> <!ATTLIST test name CDATA #REQUIRED > <!ELEMENT title (#PCDATA)> <!ELEMENT skipif (#PCDATA)> <!ELEMENT post (#PCDATA)> <!ELEMENT get (#PCDATA)> <!ELEMENT code (#PCDATA)> <!ELEMENT output (#PCDATA)> <!ELEMENT makefile (#PCDATA)> http://cvs.php.net/co.php/pear/CodeGen_PECL/manual.html?r=1.1&p=1 Index: pear/CodeGen_PECL/manual.html +++ pear/CodeGen_PECL/manual.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML ><HEAD ><TITLE >PECL_Gen - the PHP extension generator</TITLE ><META NAME="GENERATOR" CONTENT="Modular DocBook HTML Stylesheet Version 1.79"></HEAD ><BODY CLASS="book" BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#840084" ALINK="#0000FF" ><DIV CLASS="BOOK" ><A NAME="AEN1" ></A ><DIV CLASS="TITLEPAGE" ><H1 CLASS="title" ><A NAME="AEN1" ><TT CLASS="literal" >PECL_Gen</TT > - the PHP extension generator</A ></H1 ><HR></DIV ><DIV CLASS="TOC" ><DL ><DT ><B >Table of Contents</B ></DT ><DT >1. <A HREF="#AEN4" >Introduction</A ></DT ><DD ><DL ><DT >1.1. <A HREF="#AEN6" >What is it?</A ></DT ><DT >1.2. <A HREF="#AEN19" >Features</A ></DT ><DT >1.3. <A HREF="#AEN38" >How to use it</A ></DT ></DL ></DD ><DT >2. <A HREF="#AEN49" >The XML description</A ></DT ><DD ><DL ><DT >2.1. <A HREF="#AEN51" >Basics</A ></DT ><DT >2.2. <A HREF="#AEN64" >Release information</A ></DT ><DT >2.3. <A HREF="#AEN96" >Dependencies</A ></DT ><DD ><DL ><DT >2.3.1. <A HREF="#AEN119" ><TT CLASS="literal" >--with...</TT ></A ></DT ><DT >2.3.2. <A HREF="#AEN138" >Libraries</A ></DT ><DT >2.3.3. <A HREF="#AEN152" >Header files</A ></DT ></DL ></DD ><DT >2.4. <A HREF="#AEN167" >Custom code</A ></DT ><DT >2.5. <A HREF="#AEN178" >Functions</A ></DT ><DD ><DL ><DT >2.5.1. <A HREF="#AEN188" >Public functions</A ></DT ><DT >2.5.2. <A HREF="#AEN232" >Internal functions</A ></DT ></DL ></DD ><DT >2.6. <A HREF="#AEN280" >Constants</A ></DT ><DT >2.7. <A HREF="#AEN297" ><TT CLASS="literal" >php.ini</TT > parameters and internal variables</A ></DT ><DT >2.8. <A HREF="#AEN369" >Resources</A ></DT ><DD ><DL ><DT >2.8.1. <A HREF="#AEN391" >Resource creation and destruction</A ></DT ></DL ></DD ><DT >2.9. <A HREF="#AEN402" >Classes</A ></DT ><DT >2.10. <A HREF="#AEN405" >Streams</A ></DT ><DT >2.11. <A HREF="#AEN408" >config.m4 fragments</A ></DT ><DT >2.12. <A HREF="#AEN415" >Makefile fragments</A ></DT ><DT >2.13. <A HREF="#AEN422" >Tests</A ></DT ></DL ></DD ><DT >3. <A HREF="#AEN427" >XML input parsing</A ></DT ><DD ><DL ><DT >3.1. <A HREF="#AEN429" >Includes</A ></DT ><DD ><DL ><DT >3.1.1. <A HREF="#AEN442" >External entities</A ></DT ><DT >3.1.2. <A HREF="#AEN445" >XInclude</A ></DT ><DT >3.1.3. <A HREF="#AEN448" ><CODE CLASS="sgmltag" >code</CODE > tags</A ></DT ></DL ></DD ></DL ></DD ></DL ></DIV ><DIV CLASS="LOT" ><DL CLASS="LOT" ><DT ><B >List of Examples</B ></DT ><DT >2-1. <A HREF="#AEN61" >Extension basics</A ></DT ><DT >2-2. <A HREF="#AEN73" >Release information</A ></DT ><DT >2-3. <A HREF="#AEN84" >License</A ></DT ><DT >2-4. <A HREF="#AEN93" >A logo image</A ></DT ><DT >2-5. <A HREF="#AEN116" >Dependencies</A ></DT ><DT >2-6. <A HREF="#AEN134" ><TT CLASS="literal" >--with...</TT ></A ></DT ><DT >2-7. <A HREF="#AEN149" >Library dependencies</A ></DT ><DT >2-8. <A HREF="#AEN164" >Header file dependencies</A ></DT ><DT >2-9. <A HREF="#AEN243" ><TT CLASS="literal" >MINIT()</TT ></A ></DT ><DT >2-10. <A HREF="#AEN274" ><TT CLASS="literal" >MINFO()</TT ></A ></DT ><DT >2-11. <A HREF="#AEN294" >PHP Constants</A ></DT ><DT >2-12. <A HREF="#AEN362" >Globals</A ></DT ><DT >2-13. <A HREF="#AEN366" >Globals</A ></DT ><DT >2-14. <A HREF="#AEN388" >Resources</A ></DT ><DT >2-15. <A HREF="#AEN395" >Resource creation</A ></DT ><DT >2-16. <A HREF="#AEN399" >Resource destruction</A ></DT ><DT >2-17. <A HREF="#AEN412" >config.m4 additions</A ></DT ><DT >2-18. <A HREF="#AEN419" >Makefile fragments</A ></DT ></DL ></DIV ><DIV CLASS="chapter" ><HR><H1 ><A NAME="AEN4" ></A >Chapter 1. Introduction</H1 ><DIV CLASS="section" ><H2 CLASS="section" ><A NAME="AEN6" >1.1. What is it?</A ></H2 ><P >&#13; <TT CLASS="literal" >PECL_Gen</TT > is a tool that can automatically create the basic framework for a PHP extension from a rather simple XML specification file. </P ><P >&#13; It also supports the simpler (but less powerful) prototype file format as used by the shell script <TT CLASS="literal" >ext_skel</TT > that is distributed togehter with the PHP source code. </P ><P >&#13; <TT CLASS="literal" >PECL_Gen</TT >, unlike the older <TT CLASS="literal" >ext_skel</TT > solution, is a 100% PHP 5 bases solution and does not require any external tools like <TT CLASS="literal" >awk</TT > or <TT CLASS="literal" >sed</TT >. It only uses PHP functions that are always enabled in a default build so it should be usable on any platform that PHP itself runs on. </P ><P >&#13; The code generated by <TT CLASS="literal" >PECL_Gen</TT > is designed to work with both the PHP 4 and PHP 5 extension APIs, PHP 5 is only required for the conversion of the XML spec file to C/C++ code. </P ></DIV ><DIV CLASS="section" ><HR><H2 CLASS="section" ><A NAME="AEN19" >1.2. Features</A ></H2 ><P >&#13; <TT CLASS="literal" >pecl-gen</TT > tries to support as many extension writing aspects as possible. This currently includes code and documentation generation for: <P ></P ><TABLE BORDER="0" ><TBODY ><TR ><TD >functions</TD ></TR ><TR ><TD >constants</TD ></TR ><TR ><TD ><TT CLASS="literal" >php.ini</TT > configuration directives</TD ></TR ><TR ><TD >resource types</TD ></TR ><TR ><TD >per-thread global variables</TD ></TR ></TBODY ></TABLE ><P ></P > </P ><P >&#13; <TT CLASS="literal" >pecl-gen</TT > also generates <TT CLASS="filename" >config.m4</TT > configuration files for Unix-like build environments, VisualStudio <TT CLASS="filename" >*.dsp</TT > project files for Windows and the <TT CLASS="filename" >package.xml</TT > files needed for PEAR/PECL packaging. </P ><P >&#13; DocBook XML documentation templates suitable for inclusion in the PHP or PEAR manual are generated in the hope that it will ease the task of documenting extension. </P ><P >&#13; Test script templates for automatic regression testing are already created but due to some missing features within the "<TT CLASS="literal" >make test</TT >" infrastructure it is not possible to use the generated tests with standalone PECL extensions right now. </P ></DIV ><DIV CLASS="section" ><HR><H2 CLASS="section" ><A NAME="AEN38" >1.3. How to use it</A ></H2 ><P >&#13; There are currently three different modes of operation for <TT CLASS="literal" >pecl-gen</TT >. In its default mode it can create a complete ready-to-compile extension from an XML description (documented in the next chapter). In <TT CLASS="literal" >ext_skel</TT > compatibility mode it generates the extension from some command line parameters and an optional function prototype file and in immediate mode it just takes a function prototype from command line and writes a C code skeleton for just that function to standard output. </P ><P >&#13; <TT CLASS="literal" >ext_skel</TT > compatibility and immediate mode are not documented here, please refer to the original <TT CLASS="literal" >ext_skel</TT > documentation instead. </P ><P >&#13; Below you find a hardcopy of the <TT CLASS="literal" >pecl-gen --help</TT > output: </P ><PRE CLASS="screen" >&#13;pecl-gen [-h] [--extname=name] [--proto=file] [--skel=dir] [--stubs=file] [--no-help] [--xml[=file]] [--full-xml] [--function=proto] [specfile.xml] -h|--help this message --force overwrite existing directories --function create a function skeleton from a proto right away --version show version info the following options are inherited from ext_skel: --extname=module module is the name of your extension --proto=file file contains prototypes of functions to create --xml generate xml documentation to be added to phpdoc-cvs these wait for functionality to be implemented and are ignored for now ... --stubs=file generate only function stubs in file --no-help don't try to be nice and create comments in the code and helper functions to test if the module compiled these are accepted for backwards compatibility reasons but not used ... --full-xml generate xml documentation for a self-contained extension (this was also a no-op in ext_skel) --skel=dir path to the skeleton directory (skeleton stuff is now self-contained) </PRE ></DIV ></DIV ><DIV CLASS="chapter" ><HR><H1 ><A NAME="AEN49" ></A >Chapter 2. The XML description</H1 ><DIV CLASS="section" ><H2 CLASS="section" ><A NAME="AEN51" >2.1. Basics</A ></H2 ><P >&#13; The top level container tag describing an extension is the <CODE CLASS="sgmltag" >extension</CODE > tag. The name of the extension is given in the <TT CLASS="literal" >name</TT > attribute. The extension name has to be a valid C name as it is used as both the extensions directory name and the base name for several C symbols within the generated C code. </P ><P >&#13; The tags <CODE CLASS="sgmltag" >summary</CODE > and <CODE CLASS="sgmltag" >description</CODE > should be added at the very top of your extensions. The summary should be a short one-line description of the extension while the actually description can be as detailed as you like. Both are later used to generate the <TT CLASS="literal" >package.xml</TT > file and the documentation for your extension. The summary line is also put into the <TT CLASS="literal" >phpinfo()</TT > output of your extension. </P ><DIV CLASS="example" ><A NAME="AEN61" ></A ><P ><B >Example 2-1. Extension basics</B ></P ><PRE CLASS="programlisting" >&#13; &#60;extension name="sample"&#62; &#60;summary&#62;A sample PHP extension&#60;/summary&#62; &#60;description&#62; This is a sample extension specification showing how to use PECL_Gen for extension generation. &#60;/description&#62; ... </PRE ></DIV ></DIV ><DIV CLASS="section" ><HR><H2 CLASS="section" ><A NAME="AEN64" >2.2. Release information</A ></H2 ><P >&#13; The release information for your extension should include the extension authors and maintainers, the version number, state and release date, the chosen license and maybe a change log describing previous releases. It is also possible to specify an image file to be used as a product logo with the <TT CLASS="literal" >phpinfo()</TT > output block for the extension. </P ><P >&#13; The <CODE CLASS="sgmltag" >maintainers</CODE >, <CODE CLASS="sgmltag" >release</CODE > and <CODE CLASS="sgmltag" >changelog</CODE > tags specifications are identical to those in the PEAR <TT CLASS="literal" >package.xml</TT > specification so please refer to the PEAR documentation here. </P ><DIV CLASS="example" ><A NAME="AEN73" ></A ><P ><B >Example 2-2. Release information</B ></P ><PRE CLASS="programlisting" >&#13;.... &#60;maintainers&#62; &#60;maintainer&#62; &#60;user&#62;hholzgra&#60;/user&#62; &#60;name&#62;Hartmut Holzgraefe&#60;/name&#62; &#60;email&#62;hartmut@php.net&#60;/email&#62; &#60;role&#62;lead&#60;/role&#62; &#60;/maintainer&#62; &#60;/maintainers&#62; &#60;release&#62; &#60;version&#62;1.0&#60;/version&#62; &#60;date&#62;2002-07-09&#60;/date&#62; &#60;state&#62;stable&#60;/state&#62; &#60;notes&#62; The sample extension is now stable &#60;/notes&#62; &#60;/release&#62; &#60;changelog&#62; &#60;release&#62; &#60;version&#62;0.5&#60;/version&#62; &#60;date&#62;2002-07-05&#60;/date&#62; &#60;state&#62;beta&#60;/state&#62; &#60;notes&#62;First beta version&#60;/notes&#62; &#60;release&#62; &#60;release&#62; &#60;version&#62;0.1&#60;/version&#62; &#60;date&#62;2002-07-01&#60;/date&#62; &#60;state&#62;alpha&#60;/state&#62; &#60;notes&#62;First alpha version&#60;/notes&#62; &#60;release&#62; &#60;/changelog&#62;.... </PRE ></DIV ><P >&#13; The <CODE CLASS="sgmltag" >license</CODE > tag is a little more restrictive as its <TT CLASS="literal" >package.xml</TT > counterpart as it is used to decide which license text should actually be written to the <TT CLASS="literal" >LICENSE</TT >. For now you have to specify either <TT CLASS="literal" >PHP</TT >, <TT CLASS="literal" >BSD</TT > or <TT CLASS="literal" >LGPL</TT >, any other value is taken as '<SPAN CLASS="emphasis" ><I CLASS="emphasis" >unknown</I ></SPAN >'. </P ><DIV CLASS="example" ><A NAME="AEN84" ></A ><P ><B >Example 2-3. License</B ></P ><PRE CLASS="programlisting" >&#13;.... &#60;license&#62;PHP&#60;/license&#62;.... </PRE ></DIV ><P >&#13; A logo to be used within the extensions <TT CLASS="literal" >phpinfo()</TT > block can be specified using the <CODE CLASS="sgmltag" >logo</CODE > tag. The actual file name of the logo image has to be given in the <TT CLASS="literal" >scr=...</TT > attribute, Its MIME type defaults to <TT CLASS="literal" >image/gif</TT > unless a different type is specified using the <TT CLASS="literal" >mimetype=...</TT > attribute. Automatic MIME type detection is planned for a future release. </P ><DIV CLASS="example" ><A NAME="AEN93" ></A ><P ><B >Example 2-4. A logo image</B ></P ><PRE CLASS="programlisting" >&#13;.... &#60;logo src="sample_logo.gif" mimetype="image/gif" /&#62;.... </PRE ></DIV ></DIV ><DIV CLASS="section" ><HR><H2 CLASS="section" ><A NAME="AEN96" >2.3. Dependencies</A ></H2 ><P >&#13; Dependencies are specified within the <CODE CLASS="sgmltag" >deps</CODE > environment. Within the <CODE CLASS="sgmltag" >deps</CODE > itself it is possible to set the programming language and target platforms using the <TT CLASS="literal" >language=...</TT > and <TT CLASS="literal" >platform=...</TT > attributes. </P ><P >&#13; Supported languages are C (<TT CLASS="literal" >lang="c"</TT >) and C++ (<TT CLASS="literal" >language="cpp"</TT >). The language selection does not influence code generation itself (<TT CLASS="literal" >pecl-gen</TT > always generates C code) but the way extensions are compiled and linked. C++ should only be selected to interface to external C++ libraries. </P ><P >&#13; Supported platforms are currently Unix-like systems (<TT CLASS="literal" >platform="unix"</TT >), Microsoft Windows (<TT CLASS="literal" >platform="win32"</TT >) or both (<TT CLASS="literal" >platform="all"</TT >). </P ><P > <CODE CLASS="sgmltag" >with</CODE >, <CODE CLASS="sgmltag" >lib</CODE > and <CODE CLASS="sgmltag" >header</CODE > tags may be used within the <CODE CLASS="sgmltag" >deps</CODE > section to add configure switches and library and header file dependencies. </P ><DIV CLASS="example" ><A NAME="AEN116" ></A ><P ><B >Example 2-5. Dependencies</B ></P ><PRE CLASS="programlisting" >&#13;.... &#60;deps language="cpp" platform="win32"&#62; ... &#60;/deps&#62;.... </PRE ></DIV ><DIV CLASS="section" ><HR><H3 CLASS="section" ><A NAME="AEN119" >2.3.1. <TT CLASS="literal" >--with...</TT ></A ></H3 ><P >&#13; When building an extension on Unix-like systems or within the Cygwin environment under Windows the <TT CLASS="literal" >configure</TT > script will try to figure out where external libraries and header files needed by an extension are installed on the build system. Using a "with" option it is possible to specify where to actually look for libraries and headers. This way it is possible to override search paths if things are not installed in the default system paths or to specify the exact version of a package to be used if multiple versions are installed on the target system. </P ><P >&#13; The <CODE CLASS="sgmltag" >with</CODE > tag takes three attributes: <TT CLASS="literal" >name=...</TT > for the actual name of the "with" option, <TT CLASS="literal" >testfile</TT > for the relative path of a file to check for while running the <TT CLASS="literal" >configure</TT > script and a list of default paths to check if no path is given as an argument to the "with" option in <TT CLASS="literal" >defaults</TT >. </P ><P >&#13; Name and defaults are set to the extension base name and "/usr:/usr/local" if no values are given. The testfile attribute is mandatory. </P ><P >&#13; Textual data enclosed by the <CODE CLASS="sgmltag" >with</CODE > is used to describe the "with" option in the output of <TT CLASS="literal" >configure --help</TT > calls. </P ><DIV CLASS="example" ><A NAME="AEN134" ></A ><P ><B >Example 2-6. <TT CLASS="literal" >--with...</TT ></B ></P ><PRE CLASS="programlisting" > .... &#60;with defaults='/usr:/usr/local' testfile='include/sample.h'&#62;sample install&#60;/with&#62; .... </PRE ></DIV ></DIV ><DIV CLASS="section" ><HR><H3 CLASS="section" ><A NAME="AEN138" >2.3.2. Libraries</A ></H3 ><P >&#13; Needed external libraries are specified using the <CODE CLASS="sgmltag" >lib</CODE > tag. The <TT CLASS="literal" >name=...</TT > attribute is mandatory and takes the library base name. A library dependency by the name "sample" is actually referring to a library file named <TT CLASS="filename" >libsample.a</TT > for a static or <TT CLASS="filename" >libsample.so</TT > for a dynamic library on Unix-like systems or to <TT CLASS="filename" >sample.DLL</TT > on Windows. </P ><P >&#13; It is possible to specify the name of a function symbol expected to be provided by the library using the <TT CLASS="literal" >function=...</TT > attribute. This function symbol is being looked for when <TT CLASS="literal" >configure</TT > is run for the extension. This way it is possible to verify that the right version of a library was found. With VisualStudio on windows it is not possible to perform this check, in this case the library is just added to the project file. </P ><DIV CLASS="example" ><A NAME="AEN149" ></A ><P ><B >Example 2-7. Library dependencies</B ></P ><PRE CLASS="programlisting" >&#13;.... &#60;lib name="sample_u" platform="unix" function="sample_v2" /&#62; &#60;lib name="sample_w" platform="win32" /&#62; &#60;lib name="sample" platform="all" /&#62;.... </PRE ></DIV ></DIV ><DIV CLASS="section" ><HR><H3 CLASS="section" ><A NAME="AEN152" >2.3.3. Header files</A ></H3 ><P >&#13; It is possible to specify header files needed by the extension using the <CODE CLASS="sgmltag" >header</CODE >. Any headers specified have to exist in the include path set for compiling (see also the section on <TT CLASS="literal" >--with</TT > above). <TT CLASS="literal" >#include</TT > statements for the specified headers are the last ones to be put into the generated code unless you set the <TT CLASS="literal" >prepend="yes"</TT > attribute to have it put in front of the other <TT CLASS="literal" >#include</TT >s. </P ><P >&#13; By default header files are searched for in the <TT CLASS="literal" >include</TT > subdirectory of the path given in <CODE CLASS="sgmltag" >with</CODE >. If a different relative path needs to be used it can be defined using the <TT CLASS="literal" >path</TT > attribute. </P ><DIV CLASS="example" ><A NAME="AEN164" ></A ><P ><B >Example 2-8. Header file dependencies</B ></P ><PRE CLASS="programlisting" >&#13;.... &#60;header name="include_me_first.h" prepend="yes" /&#62; &#60;header name="sample.h" /&#62; &#60;header name="foobar.h" path="include/foo/bar" /&#62; .... </PRE ></DIV ></DIV ></DIV ><DIV CLASS="section" ><HR><H2 CLASS="section" ><A NAME="AEN167" >2.4. Custom code</A ></H2 ><P >&#13; Custom code may be added to your extension source files using the <CODE CLASS="sgmltag" >code</CODE > tags. The <TT CLASS="literal" >role=...</TT > and <TT CLASS="literal" >position=...</TT > tags specify the actual place in there generated source files where your code should be inserted. </P ><P >&#13; Possible roles are '<TT CLASS="literal" >code</TT >' (default) for the generated C or C++ code file and '<TT CLASS="literal" >header</TT >' header file. Possible positions are '<TT CLASS="literal" >top</TT >' and '<TT CLASS="literal" >bottom</TT >' (default) for insertion near the beginning or end of the generated file. </P ></DIV ><DIV CLASS="section" ><HR><H2 CLASS="section" ><A NAME="AEN178" >2.5. Functions</A ></H2 ><P >&#13; Three different kinds of functions may be defined using the <CODE CLASS="sgmltag" >function</CODE > tag: public, internal and private functions. Public functions are functions you want to make available at the PHP code level, internal functions are C functions to be used by the PHP extension API and private functions are static C helper functions to be used within your extension. </P ><P >&#13; Public function names should by convention be prefixed with the extension name followed by an underscore, internal functions are one of <TT CLASS="literal" >MINIT</TT >, <TT CLASS="literal" >MSHUTDOWN</TT >, <TT CLASS="literal" >RINIT</TT >, <TT CLASS="literal" >RSHUTDOWN</TT > or <TT CLASS="literal" >MINFO</TT >, and private functions may have any legal C function name (unless you experience duplicate symbol errors while compiling or linking the extension). </P ><DIV CLASS="section" ><HR><H3 CLASS="section" ><A NAME="AEN188" >2.5.1. Public functions</A ></H3 ><P >&#13; The definition of a public PHP function requires the attributes <TT CLASS="literal" >role="public"</TT > and <TT CLASS="literal" >name=...</TT > and at least the <CODE CLASS="sgmltag" >proto</CODE > tag to be set. </P ><P >&#13; The function name may be any valid C name. To comply to PHP coding conventions a public function provided by an extension should always be prefixed by the extension name though. </P ><P >&#13; The function prototype specified using the <CODE CLASS="sgmltag" >proto</CODE > tag is parsed to extract the return type, the function name and the argument list. The function name in the prototype has to match the name attribute given in the <CODE CLASS="sgmltag" >function</CODE >. </P ><P >&#13; Valid types to be used for arguments and the return type are: <P ></P ><TABLE BORDER="0" ><TBODY ><TR ><TD ><SPAN CLASS="type" >bool</SPAN ></TD ></TR ><TR ><TD ><SPAN CLASS="type" >int</SPAN ></TD ></TR ><TR ><TD ><SPAN CLASS="type" >float</SPAN ></TD ></TR ><TR ><TD ><SPAN CLASS="type" >string</SPAN ></TD ></TR ><TR ><TD ><SPAN CLASS="type" >array</SPAN ></TD ></TR ><TR ><TD ><SPAN CLASS="type" >object</SPAN ></TD ></TR ><TR ><TD ><SPAN CLASS="type" >mixed</SPAN ></TD ></TR ><TR ><TD ><SPAN CLASS="type" >callback</SPAN ></TD ></TR ><TR ><TD ><SPAN CLASS="type" >resource</SPAN > <SPAN CLASS="emphasis" ><I CLASS="emphasis" >[typename]</I ></SPAN ></TD ></TR ><TR ><TD ><SPAN CLASS="type" >stream</SPAN ></TD ></TR ></TBODY ></TABLE ><P ></P > Argument names in prototypes are not prepended by a <TT CLASS="literal" >$</TT > sign by convention. </P ><P >&#13; Function documentation should be given using the <CODE CLASS="sgmltag" >summary</CODE > tag for a one line description and the <CODE CLASS="sgmltag" >description</CODE > tag for a more detailed description. Both are copied to the generated DocBook XML documentation for that function. Within <CODE CLASS="sgmltag" >description</CODE > DocBook tags may be used. Be aware though that while <B CLASS="command" >pecl-gen</B > accepts this validating XML parsers may complain when reading/validating an extension specification file. </P ><P >&#13; Skeleton code for parameter parsing and result passing is generated if no <CODE CLASS="sgmltag" >code</CODE > fragment is specified for a function. A <CODE CLASS="sgmltag" >code</CODE > section is inserted right after the generated parameter parsing code. Setting a return value is up to the code fragment if any is given, adding a template doesn't make sense in this case. </P ><DIV CLASS="note" ><P ></P ><TABLE CLASS="note" WIDTH="100%" BORDER="0" ><TR ><TD WIDTH="25" ALIGN="CENTER" VALIGN="TOP" ><IMG SRC="../images/note.gif" HSPACE="5" ALT="Note"></TD ><TD ALIGN="LEFT" VALIGN="TOP" ><P >&#13; Maybe some stuff regarding actual coding should be added here? </P ></TD ></TR ></TABLE ></DIV ></DIV ><DIV CLASS="section" ><HR><H3 CLASS="section" ><A NAME="AEN232" >2.5.2. Internal functions</A ></H3 ><P >&#13; The definition of an internal function requires just the <TT CLASS="literal" >role="internal"</TT > and <TT CLASS="literal" >name=...</TT > attributes. The name can only be one of the following: <P ></P ><DIV CLASS="variablelist" ><DL ><DT ><TT CLASS="literal" >MINIT</TT ></DT ><DD ><P >&#13; The module initialization function. This is called once at startup of a PHP server module or standalone (CLI or CGI) binary. </P ><DIV CLASS="example" ><A NAME="AEN243" ></A ><P ><B >Example 2-9. <TT CLASS="literal" >MINIT()</TT ></B ></P ><PRE CLASS="programlisting" >&#13;... &#60;function role="internal" name="MINIT"&#62; &#60;code&#62; &#60;![CDATA[ int dummy = 42; dummy = dummy; ]]&#62; &#60;/code&#62; &#60;/function&#62;.... </PRE ></DIV ></DD ><DT ><TT CLASS="literal" >MSHUTDOWN</TT ></DT ><DD ><P >&#13; The module shutdown function. This is called once when the PHP server module or standalone binary is properly terminated. It may not be called on program crashes or other critical errors. </P ></DD ><DT ><TT CLASS="literal" >RINIT</TT ></DT ><DD ><P >&#13; The request shutdown function. This is called by PHP server modules before actually executing a PHP script request or once right after <TT CLASS="literal" >MINIT()</TT > for standalone binaries (CGI or CLI). </P ></DD ><DT ><TT CLASS="literal" >RSHUTDOWN</TT ></DT ><DD ><P >&#13; The request shutdown function. This is called by PHP server modules after execution of PHP code has been finished or terminated. Is called even if critical PHP errors occurred but you can not rely on it being called on critical errors or crashes on the C level. </P ></DD ><DT ><TT CLASS="literal" >MINFO</TT ></DT ><DD ><P >&#13; The <TT CLASS="literal" >phpinfo()</TT > handler for this extension. It will be called whenever <TT CLASS="literal" >phpinfo()</TT > is invoked or when a standalone PHP binary is called with the <TT CLASS="literal" >-i</TT > command line option. </P ><P >&#13; The default code generated when no <CODE CLASS="sgmltag" >code</CODE > section is given includes the extension name, summary line and release version and date, the optional logo image if specified, and the global and actual values of all <TT CLASS="literal" >php.ini</TT > directives specified. </P ><DIV CLASS="example" ><A NAME="AEN274" ></A ><P ><B >Example 2-10. <TT CLASS="literal" >MINFO()</TT ></B ></P ><PRE CLASS="programlisting" >&#13;... &#60;function role='internal' name='MINFO'&#62; &#60;code&#62; &#60;![CDATA[ php_info_print_table_start(); php_info_print_table_header(2, "test", "table"); php_info_print_table_end(); ]]&#62; &#60;/code&#62; &#60;/function&#62;.... </PRE ></DIV ></DD ></DL ></DIV > </P ><P >&#13; <CODE CLASS="sgmltag" >code</CODE > sections for the internal functions may be written as if they were C function bodies, including local variable definitions. </P ></DIV ></DIV ><DIV CLASS="section" ><HR><H2 CLASS="section" ><A NAME="AEN280" >2.6. Constants</A ></H2 ><P >&#13; PHP constants are defined using <CODE CLASS="sgmltag" >constant</CODE > tags within the <CODE CLASS="sgmltag" >constants</CODE > environment. </P ><P >&#13; The actual constant name, type and value are specified using the <TT CLASS="literal" >name=...</TT >, <TT CLASS="literal" >type=...</TT > and <TT CLASS="literal" >value=...</TT > attributes. The constant name has to be a valid C name. PHP constant names should use uppercase letters only by convention. Possible types are "string", "int" and "float", the possible values depend on the type. For "int" and "float" you may use either numeric strings or the names of C constants (either true ANSI C/C++ constants or values <TT CLASS="literal" >#define</TT >d using the C preprocessor. "string" values are always used "as is", no constants may be used here. </P ><P >&#13; It is sufficient to specify a constant <TT CLASS="literal" >name</TT > only if a C integer constant should be available under the same name in PHP, too. </P ><P >&#13; A descriptive text may be given as content of the <CODE CLASS="sgmltag" >constant</CODE > tag. This text will be used when generation the DocBook XML documentation. </P ><DIV CLASS="example" ><A NAME="AEN294" ></A ><P ><B >Example 2-11. PHP Constants</B ></P ><PRE CLASS="programlisting" >&#13;.... &#60;constants&#62; &#60;constant name="SAMPLE_INT" type="int" value="42"&#62; A sample integer constant. &#60;/constant&#62; &#60;constant name="SAMPLE_FLOAT" type="float" value="3.14"&#62; A sample floating point constant. &#60;/constant&#62; &#60;constant name="SAMPLE_FLOAT" type="float" value="M_PI"&#62; A sample floating point constant using a #defined constant &#60;/constant&#62; &#60;constant name="SAMPLE_STRING" type="string" value="Hello World!"&#62; A sample string constant. &#60;/constant&#62; &#60;constant name="MY_CONST"&#62; A shortcat for #defined integer constants &#60;/constant&#62; &#60;/constants&#62;.... </PRE ></DIV ></DIV ><DIV CLASS="section" ><HR><H2 CLASS="section" ><A NAME="AEN297" >2.7. <TT CLASS="literal" >php.ini</TT > parameters and internal variables</A ></H2 ><P >&#13; An extension may define variables that are global to either the complete extension or to a specific request. True globals that are global to the complete extensions do not need any registration so they can be defined using C code within the global <CODE CLASS="sgmltag" >code</CODE > tag. </P ><P >&#13; Module globals that are only global to a single request need to be managed to ensure thread safety and initialization on request initialization. <TT CLASS="literal" >php.ini</TT > directive values are also stored as module globals but need some additional definitions. </P ><P >&#13; All global definitions have to be put into a <CODE CLASS="sgmltag" >globals</CODE > environment. Simple module globals are defined using the <CODE CLASS="sgmltag" >global</CODE > tag. <TT CLASS="literal" >php.ini</TT > directives are defined using the <CODE CLASS="sgmltag" >phpini</CODE > tag. </P ><P >&#13; A <CODE CLASS="sgmltag" >global</CODE > definition requires the <TT CLASS="literal" >name=...</TT > and <TT CLASS="literal" >type=...</TT > attributes to be set as valid C names and types. Which C types are allowed depends on what type definitions have been included from header files. The available types are not known when <TT CLASS="literal" >pecl-gen</TT > parses the XML specification so that types are only checked for valid name format here. Specifying a type that is not a basic C type or defined in any included file will lead to error messages when compiling the generated extension code later. </P ><P >&#13; Initial values may be specified using the <TT CLASS="literal" >value=...</TT > attribute. This feature should only be used for simple numeric values, anything more complex should better be initialized within the extensions <TT CLASS="literal" >RINIT()</TT > function. </P ><P >&#13; <TT CLASS="literal" >php.ini</TT > directives may be defined using the <CODE CLASS="sgmltag" >phpini</CODE > within a <CODE CLASS="sgmltag" >globals</CODE > environment. To define a <TT CLASS="literal" >php.ini</TT > directive you have to specify its name, type and default value using the <TT CLASS="literal" >name=...</TT >, <TT CLASS="literal" >type=...</TT > and <TT CLASS="literal" >value=...</TT > attributes. </P ><P >&#13; Valid directive names are C variable names. The actual directive name is the extension name followed by a single dot '<TT CLASS="literal" >.</TT >' and the specified name. Valid directive types are <SPAN CLASS="type" >bool</SPAN >, <SPAN CLASS="type" >int</SPAN >, <SPAN CLASS="type" >float</SPAN > and <SPAN CLASS="type" >string</SPAN >. </P ><P >&#13; Directive default values are passed to the engine as strings, so you may not use any C constants or preprocessor macros here. The default value strings are parsed by the <TT CLASS="literal" >OnUpdate</TT > handler registered for that directive. No value checking takes place during extension code generation or compilation, this is done by the registered <TT CLASS="literal" >OnUpdate</TT > handler at runtime during request initialization. The <TT CLASS="literal" >OnUpdate</TT > handler defaults to the appropriate internal <TT CLASS="literal" >OnUpdate</TT ><SPAN CLASS="emphasis" ><I CLASS="emphasis" >type</I ></SPAN > handler unless you specify a different handler using the <TT CLASS="literal" >onupdate=...</TT > attribute. </P ><P >&#13; The directive value may be changed at any time unless you specify an <TT CLASS="literal" >access=...</TT > attribute. Possible values are: <P ></P ><DIV CLASS="variablelist" ><DL ><DT >system</DT ><DD ><P >&#13; may only be set globally in <TT CLASS="literal" >php.ini</TT > or the web server configuration </P ></DD ><DT >perdir</DT ><DD ><P >&#13; may be changed in local <TT CLASS="literal" >.htaccess</TT > files </P ></DD ><DT >user</DT ><DD ><P >may be changed by PHP code</P ></DD ><DT >all</DT ><DD ><P >may be changed by anyone at any time</P ></DD ></DL ></DIV > </P ><P >&#13; The content data of <CODE CLASS="sgmltag" >phpini</CODE > tags is used to generate documentation for the defined directive. <CODE CLASS="sgmltag" >global</CODE > definitions may also include content data but it is for internal documentation only, it is not used in DocBook XML generation (yet). </P ><DIV CLASS="example" ><A NAME="AEN362" ></A ><P ><B >Example 2-12. Globals</B ></P ><PRE CLASS="programlisting" >&#13;.... &#60;globals&#62; &#60;global name="sample_int" type="int" value="42" /&#62; &#60;global name="sample_float" type="float" value="3.14" /&#62; &#60;global name="SAMPLE_STRING" type="char *" /&#62; &#60;phpini name="my_int" type="int" value="42" onupdate="OnUpdateLong" access="all"&#62; Definition for directive "sample.my_int" &#60;/phpini&#62; &#60;/globals&#62;.... </PRE ></DIV ><P >&#13; Access to the modul globals and ini parameters is provided in a thread safe manner through the EXTNAME_G() macro (replace EXTNAME with the upper cased name of your extension). </P ><DIV CLASS="example" ><A NAME="AEN366" ></A ><P ><B >Example 2-13. Globals</B ></P ><PRE CLASS="programlisting" >&#13; &#60;extension name="foobar"&#62; ... &#60;globals&#62; &#60;global name="sample_int" type="int" value="42" /&#62; &#60;/globals&#62; ... &#60;function ...&#62; ... &#60;code&#62; ... int foo = FOOBAR_G(sample_int); // get global value ... FOOBAR_G(sample_init) = 42; // set global value ... &#60;/code&#62; &#60;/function&#62; </PRE ></DIV ></DIV ><DIV CLASS="section" ><HR><H2 CLASS="section" ><A NAME="AEN369" >2.8. Resources</A ></H2 ><P >&#13; You may define PHP resource types within a <CODE CLASS="sgmltag" >resources</CODE > environment. For each <CODE CLASS="sgmltag" >resource</CODE > you have to specify the <TT CLASS="literal" >name=...</TT > and <TT CLASS="literal" >payload=...</TT > attributes. The <TT CLASS="literal" >name</TT > has to be a valid C name and the <TT CLASS="literal" >payload</TT > has to be a valid C type specifier. The payload type can only be checked for the correctness of its form as the actual type definitions from included header files are not known to the extension generator when it generates the extension code. </P ><P >&#13; The actual resource data structure carries a pointer to the payload type. You may specify that PHP shall allocate and free the actual payload by setting the <TT CLASS="literal" >alloc=...</TT > attribute to "<TT CLASS="literal" >yes</TT >". If the payload is allocated by a library function or by yourself you should set <TT CLASS="literal" >alloc=...</TT > to "<TT CLASS="literal" >no</TT >" (the default value). </P ><P >&#13; Resources are destructed when the last variable reference refering to them is unset or at request shutdown. If your resource payload needs to be cleaned up as well you have to add an appropriate C code snippet that takes care of this using the <CODE CLASS="sgmltag" >destruct</CODE > tag. Within the destructor snippet you may refer to the allocated payload using the <TT CLASS="literal" >resource</TT > pointer variable. </P ><P >&#13; You don't need to take care of destruction yourself if your resource payload is allocated by PHP (<TT CLASS="literal" >alloc="yes"</TT >) and needs no further cleanup work besides releasing the allocated memory. </P ><DIV CLASS="example" ><A NAME="AEN388" ></A ><P ><B >Example 2-14. Resources</B ></P ><PRE CLASS="programlisting" >&#13;.... &#60;resources&#62; &#60;resource name="sample_resource" payload="float" alloc="yes"&#62; &#60;description&#62; A simple floating point resource &#60;/description&#62; &#60;!-- no &#60;destruct&#62; needed due to the alloc attribute --&#62; &#60;/resource&#62; &#60;resource name="sample_struct" payload="struct foobar" alloc="no"&#62; &#60;description&#62; A foobar resource managed by an external foobar lib. &#60;/description&#62; &#60;destruct&#62; foobar_release(resource); &#60;/destruct&#62; &#60;/resource&#62; &#60;/resources&#62;.... </PRE ></DIV ><DIV CLASS="section" ><HR><H3 CLASS="section" ><A NAME="AEN391" >2.8.1. Resource creation and destruction</A ></H3 ><P >&#13; The creation of resource instances is not defined within <CODE CLASS="sgmltag" >resource</CODE >. This is a task to be handled by public PHP functions instead. </P ><DIV CLASS="example" ><A NAME="AEN395" ></A ><P ><B >Example 2-15. Resource creation</B ></P ><PRE CLASS="screen" >&#13; &#60;function name="foo_open"&#62; &#60;proto&#62;resource foo foo_open(string path)&#60;/proto&#62; &#60;code&#62; return_res = foo_open(path); if (!return_res) RETURN_FALSE; &#60;/code&#62; &#60;/function&#62; </PRE ></DIV ><P >&#13; Resources are freed by simply removing them from the resource list that they are in. The resources destructor function is automaticly called on list removal. </P ><DIV CLASS="example" ><A NAME="AEN399" ></A ><P ><B >Example 2-16. Resource destruction</B ></P ><PRE CLASS="screen" >&#13; &#60;function name="foo_close"&#62; &#60;proto&#62;void foo_close(resource foo foores)&#60;/proto&#62; &#60;code&#62; zend_list_delete(Z_LVAL_P(foores)); &#60;/code&#62; &#60;/function&#62; </PRE ></DIV ></DIV ></DIV ><DIV CLASS="section" ><HR><H2 CLASS="section" ><A NAME="AEN402" >2.9. Classes</A ></H2 ><P >&#13; OO support is planned for a future release but not implemented yet. OO code generation may be limited to PHP 5 extensions as unlike the rest of the extension API the OO implementation changed a lot between PHP 4 and 5. </P ></DIV ><DIV CLASS="section" ><HR><H2 CLASS="section" ><A NAME="AEN405" >2.10. Streams</A ></H2 ><P >&#13; Stream filter and wrapper support is experimental and not yet added to the released code base. </P ></DIV ><DIV CLASS="section" ><HR><H2 CLASS="section" ><A NAME="AEN408" >2.11. config.m4 fragments</A ></H2 ><P >&#13; Additional configure checks can be added to the generated config.m4 file used by Unix/Cygwin builds using the <CODE CLASS="sgmltag" >configm4</CODE > tag. Using the 'position' attribute it is possible to specify whether the additional code is to be added at the top or bottom of the config.m4 file. </P ><DIV CLASS="example" ><A NAME="AEN412" ></A ><P ><B >Example 2-17. config.m4 additions</B ></P ><PRE CLASS="screen" >&#13; &#60;configm4&#62; AC_CHECK_PROG(RE2C, re2c, re2c) PHP_SUBST(RE2C) &#60;/configm4&#62; </PRE ></DIV ></DIV ><DIV CLASS="section" ><HR><H2 CLASS="section" ><A NAME="AEN415" >2.12. Makefile fragments</A ></H2 ><P >&#13; Makefile rules may be added using the <CODE CLASS="sgmltag" >makefile</CODE > for Unix/Cygwin builds. Using this it is possible to add dependencies or build rules in addition to the default and auto generated rules. </P ><DIV CLASS="example" ><A NAME="AEN419" ></A ><P ><B >Example 2-18. Makefile fragments</B ></P ><PRE CLASS="screen" >&#13; &#60;makefile&#62; $(builddir)/scanner.c: $(srcdir)/scanner.re $(RE2C) $(srcdir)/scanner.re &#62; $@ &#60;/makefile&#62; </PRE ></DIV ></DIV ><DIV CLASS="section" ><HR><H2 CLASS="section" ><A NAME="AEN422" >2.13. Tests</A ></H2 ><P >&#13; For now <TT CLASS="literal" >PECL_Gen</TT > generates one test case skeleton for every function prototype. </P ><P >&#13; Support for customizable test script generation is planned for a future release. </P ></DIV ></DIV ><DIV CLASS="chapter" ><HR><H1 ><A NAME="AEN427" ></A >Chapter 3. XML input parsing</H1 ><DIV CLASS="section" ><H2 CLASS="section" ><A NAME="AEN429" >3.1. Includes</A ></H2 ><P >&#13; The XML parser used by <TT CLASS="literal" >PECL_Gen</TT > supports inclusion of additional source files using three different ways: <P ></P ><UL ><LI ><P >external entities</P ></LI ><LI ><P >a subset of XInclude</P ></LI ><LI ><P >the <TT CLASS="literal" >source</TT > attribute of <CODE CLASS="sgmltag" >code</CODE > tags</P ></LI ></UL > </P ><DIV CLASS="section" ><HR><H3 CLASS="section" ><A NAME="AEN442" >3.1.1. External entities</A ></H3 ><P >&#13; </P ></DIV ><DIV CLASS="section" ><HR><H3 CLASS="section" ><A NAME="AEN445" >3.1.2. XInclude</A ></H3 ><P >&#13; </P ></DIV ><DIV CLASS="section" ><HR><H3 CLASS="section" ><A NAME="AEN448" >3.1.3. <CODE CLASS="sgmltag" >code</CODE > tags</A ></H3 ><P >&#13; </P ></DIV ></DIV ></DIV ></DIV ></BODY ></HTML > http://cvs.php.net/co.php/pear/CodeGen_PECL/manual.xml?r=1.1&p=1 Index: pear/CodeGen_PECL/manual.xml +++ pear/CodeGen_PECL/manual.xml <?xml version='1.0' encoding='ISO-8859-1' ?> <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "../../phpdoc/dtds/dbxml-4.1.2/docbookx.dtd" [ ]> <book> <!-- TODO: src=... is now available in a lot of places --> <title><literal>PECL_Gen</literal> - the PHP extension generator</title> <chapter> <title>Introduction</title> <section> <title>What is it?</title> <para> <literal>PECL_Gen</literal> is a tool that can automatically create the basic framework for a PHP extension from a rather simple XML specification file. </para> <para> It also supports the simpler (but less powerful) prototype file format as used by the shell script <literal>ext_skel</literal> that is distributed togehter with the PHP source code. </para> <para> <literal>PECL_Gen</literal>, unlike the older <literal>ext_skel</literal> solution, is a 100% PHP 5 bases solution and does not require any external tools like <literal>awk</literal> or <literal>sed</literal>. It only uses PHP functions that are always enabled in a default build so it should be usable on any platform that PHP itself runs on. </para> <para> The code generated by <literal>PECL_Gen</literal> is designed to work with both the PHP 4 and PHP 5 extension APIs, PHP 5 is only required for the conversion of the XML spec file to C/C++ code. </para> </section> <section> <title>Features</title> <para> <literal>pecl-gen</literal> tries to support as many extension writing aspects as possible. This currently includes code and documentation generation for: <simplelist> <member>functions</member> <member>constants</member> <member><literal>php.ini</literal> configuration directives</member> <member>resource types</member> <member>per-thread global variables</member> </simplelist> </para> <para> <literal>pecl-gen</literal> also generates <filename>config.m4</filename> configuration files for Unix-like build environments, VisualStudio <filename>*.dsp</filename> project files for Windows and the <filename>package.xml</filename> files needed for PEAR/PECL packaging. </para> <para> DocBook XML documentation templates suitable for inclusion in the PHP or PEAR manual are generated in the hope that it will ease the task of documenting extension. </para> <para> Test script templates for automatic regression testing are already created but due to some missing features within the "<literal>make test</literal>" infrastructure it is not possible to use the generated tests with standalone PECL extensions right now. </para> </section> <section> <title>How to use it</title> <para> There are currently three different modes of operation for <literal>pecl-gen</literal>. In its default mode it can create a complete ready-to-compile extension from an XML description (documented in the next chapter). In <literal>ext_skel</literal> compatibility mode it generates the extension from some command line parameters and an optional function prototype file and in immediate mode it just takes a function prototype from command line and writes a C code skeleton for just that function to standard output. </para> <para> <literal>ext_skel</literal> compatibility and immediate mode are not documented here, please refer to the original <literal>ext_skel</literal> documentation instead. </para> <para> Below you find a hardcopy of the <literal>pecl-gen --help</literal> output: </para> <screen> <![CDATA pecl-gen 0.9.0rc5,Copyright (c) 2003-2005 Hartmut Holzgraefe Usage: pecl-gen [-h] [--force] [--experimental] [--version] [--extname=name] [--proto=file] [--skel=dir] [--stubs=file] [--no-help] [--xml[=file]] [--full-xml] [--function=proto] [specfile.xml] -h|--help this message -f|--force overwrite existing directories -l|--linespecs generate #line specs -x|--experimental deprecated --function create a function skeleton from a proto right away --version show version info the following options are inherited from ext_skel: --extname=module module is the name of your extension --proto=file file contains prototypes of functions to create --xml generate xml documentation to be added to phpdoc-cvs these wait for functionality to be implemented and are ignored for now ... --stubs=file generate only function stubs in file --no-help don't try to be nice and create comments in the code and helper functions to test if the module compiled these are accepted for backwards compatibility reasons but not used ... --full-xml generate xml documentation for a self-contained extension (this was also a no-op in ext_skel) --skel=dir path to the skeleton directory (skeleton stuff is now self-contained) ]]> </screen> </section> </chapter> <chapter> <title>The XML description</title> <section> <title>Basics</title> <para> The top level container tag describing an extension is the <sgmltag>extension</sgmltag> tag. The name of the extension is given in the <literal>name</literal> attribute. The extension name has to be a valid C name as it is used as both the extensions directory name and the base name for several C symbols within the generated C code. </para> <para> The tags <sgmltag>summary</sgmltag> and <sgmltag>description</sgmltag> should be added at the very top of your extensions. The summary should be a short one-line description of the extension while the actually description can be as detailed as you like. Both are later used to generate the <literal>package.xml</literal> file and the documentation for your extension. The summary line is also put into the <literal>phpinfo()</literal> output of your extension. </para> <example> <title>Extension basics</title> <programlisting role="xml"> <![CDATA[ <extension name="sample"> <summary>A sample PHP extension</summary> <description> This is a sample extension specification showing how to use PECL_Gen for extension generation. </description> ... ]]> </programlisting> </example> </section> <section> <title>Release information</title> <para> The release information for your extension should include the extension authors and maintainers, the version number, state and release date, the chosen license and maybe a change log describing previous releases. It is also possible to specify an image file to be used as a product logo with the <literal>phpinfo()</literal> output block for the extension. </para> <para> The <sgmltag>maintainers</sgmltag>, <sgmltag>release</sgmltag> and <sgmltag>changelog</sgmltag> tags specifications are identical to those in the PEAR <literal>package.xml</literal> specification so please refer to the PEAR documentation here. </para> <example> <title>Release information</title> <programlisting> <![CDATA[.... <maintainers> <maintainer> <user>hholzgra</user> <name>Hartmut Holzgraefe</name> <email>hartmut@php.net</email> <role>lead</role> </maintainer> </maintainers> <release> <version>1.0</version> <date>2002-07-09</date> <state>stable</state> <notes> The sample extension is now stable </notes> </release> <changelog> <release> <version>0.5</version> <date>2002-07-05</date> <state>beta</state> <notes>First beta version</notes> <release> <release> <version>0.1</version> <date>2002-07-01</date> <state>alpha</state> <notes>First alpha version</notes> <release> </changelog>.... ]]> </programlisting> </example> <para> The <sgmltag>license</sgmltag> tag is a little more restrictive as its <literal>package.xml</literal> counterpart as it is used to decide which license text should actually be written to the <literal>LICENSE</literal>. For now you have to specify either <literal>PHP</literal>, <literal>BSD</literal> or <literal>LGPL</literal>, any other value is taken as '<emphasis>unknown</emphasis>'. </para> <example> <title>License</title> <programlisting role="xml"> <![CDATA[.... <license>PHP</license>.... ]]> </programlisting> </example> <para> A logo to be used within the extensions <literal>phpinfo()</literal> block can be specified using the <sgmltag>logo</sgmltag> tag. The actual file name of the logo image has to be given in the <literal>scr=...</literal> attribute, Its MIME type defaults to <literal>image/gif</literal> unless a different type is specified using the <literal>mimetype=...</literal> attribute. Automatic MIME type detection is planned for a future release. </para> <example> <title>A logo image</title> <programlisting role="xml"> <![CDATA[.... <logo src="sample_logo.gif" mimetype="image/gif" />.... ]]> </programlisting> </example> </section> <section> <title>Dependencies</title> <para> Dependencies are specified within the <sgmltag>deps</sgmltag> environment. Within the <sgmltag>deps</sgmltag> itself it is possible to set the programming language and target platforms using the <literal>language=...</literal> and <literal>platform=...</literal> attributes. </para> <para> Supported languages are C (<literal>lang="c"</literal>) and C++ (<literal>language="cpp"</literal>). The language selection does not influence code generation itself (<literal>pecl-gen</literal> always generates C code) but the way extensions are compiled and linked. C++ should only be selected to interface to external C++ libraries. </para> <para> Supported platforms are currently Unix-like systems (<literal>platform="unix"</literal>), Microsoft Windows (<literal>platform="win32"</literal>) or both (<literal>platform="all"</literal>). </para> <para> <sgmltag>with</sgmltag>, <sgmltag>lib</sgmltag> and <sgmltag>header</sgmltag> tags may be used within the <sgmltag>deps</sgmltag> section to add configure switches and library and header file dependencies. </para> <example> <title>Dependencies</title> <programlisting> <![CDATA[.... <deps language="cpp" platform="win32"> ... </deps>.... ]]> </programlisting> </example> <section> <title><literal>--with...</literal></title> <para> When building an extension on Unix-like systems or within the Cygwin environment under Windows the <literal>configure</literal> script will try to figure out where external libraries and header files needed by an extension are installed on the build system. Using a "with" option it is possible to specify where to actually look for libraries and headers. This way it is possible to override search paths if things are not installed in the default system paths or to specify the exact version of a package to be used if multiple versions are installed on the target system. </para> <para> The <sgmltag>with</sgmltag> tag takes three attributes: <literal>name=...</literal> for the actual name of the "with" option, <literal>testfile</literal> for the relative path of a file to check for while running the <literal>configure</literal> script and a list of default paths to check if no path is given as an argument to the "with" option in <literal>defaults</literal>. </para> <para> Name and defaults are set to the extension base name and "/usr:/usr/local" if no values are given. The testfile attribute is mandatory. </para> <para> Textual data enclosed by the <sgmltag>with</sgmltag> is used to describe the "with" option in the output of <literal>configure --help</literal> calls. </para> <example> <title><literal>--with...</literal></title> <programlisting> <![CDATA[ .... <with defaults='/usr:/usr/local' testfile='include/sample.h'>sample install</with> .... ]]> </programlisting> </example> </section> <section> <title>Libraries</title> <para> Needed external libraries are specified using the <sgmltag>lib</sgmltag> tag. The <literal>name=...</literal> attribute is mandatory and takes the library base name. A library dependency by the name "sample" is actually referring to a library file named <filename>libsample.a</filename> for a static or <filename>libsample.so</filename> for a dynamic library on Unix-like systems or to <filename>sample.DLL</filename> on Windows. </para> <para> It is possible to specify the name of a function symbol expected to be provided by the library using the <literal>function=...</literal> attribute. This function symbol is being looked for when <literal>configure</literal> is run for the extension. This way it is possible to verify that the right version of a library was found. With VisualStudio on windows it is not possible to perform this check, in this case the library is just added to the project file. </para> <example> <title>Library dependencies</title> <programlisting> <![CDATA[.... <lib name="sample_u" platform="unix" function="sample_v2" /> <lib name="sample_w" platform="win32" /> <lib name="sample" platform="all" />.... ]]> </programlisting> </example> </section> <section> <title>Header files</title> <para> It is possible to specify header files needed by the extension using the <sgmltag>header</sgmltag>. Any headers specified have to exist in the include path set for compiling (see also the section on <literal>--with</literal> above). <literal>#include</literal> statements for the specified headers are the last ones to be put into the generated code unless you set the <literal>prepend="yes"</literal> attribute to have it put in front of the other <literal>#include</literal>s. </para> <para> By default header files are searched for in the <literal>include</literal> subdirectory of the path given in <sgmltag>with</sgmltag>. If a different relative path needs to be used it can be defined using the <literal>path</literal> attribute. </para> <!-- TODO: is this still true? <note> <para> <literal>config.m4</literal>/<literal>configure</literal> checks for header file availability has not been added yet. </para> </note> --> <example> <title>Header file dependencies</title> <programlisting> <![CDATA[.... <header name="include_me_first.h" prepend="yes" /> <header name="sample.h" /> <header name="foobar.h" path="include/foo/bar" /> .... ]]> </programlisting> </example> </section> <!-- TODO: will we ever support this? would make sense for e.g. pkgtools? <section> <title>External programs</title> <para> Not supported yet. </para> </section> <section> <title>Other files</title> <para> Not supported yet. </para> </section> --> </section> <section> <title>Custom code</title> <para> Custom code may be added to your extension source files using the <sgmltag>code</sgmltag> tags. The <literal>role=...</literal> and <literal>position=...</literal> tags specify the actual place in there generated source files where your code should be inserted. </para> <para> Possible roles are '<literal>code</literal>' (default) for the generated C or C++ code file and '<literal>header</literal>' header file. Possible positions are '<literal>top</literal>' and '<literal>bottom</literal>' (default) for insertion near the beginning or end of the generated file. </para> </section> <section> <title>Functions</title> <para> Three different kinds of functions may be defined using the <sgmltag>function</sgmltag> tag: public, internal and private functions. Public functions are functions you want to make available at the PHP code level, internal functions are C functions to be used by the PHP extension API and private functions are static C helper functions to be used within your extension. </para> <para> Public function names should by convention be prefixed with the extension name followed by an underscore, internal functions are one of <literal>MINIT</literal>, <literal>MSHUTDOWN</literal>, <literal>RINIT</literal>, <literal>RSHUTDOWN</literal> or <literal>MINFO</literal>, and private functions may have any legal C function name (unless you experience duplicate symbol errors while compiling or linking the extension). </para> <section> <title>Public functions</title> <para> The definition of a public PHP function requires the attributes <literal>role="public"</literal> and <literal>name=...</literal> and at least the <sgmltag>proto</sgmltag> tag to be set. </para> <para> The function name may be any valid C name. To comply to PHP coding conventions a public function provided by an extension should always be prefixed by the extension name though. </para> <para> The function prototype specified using the <sgmltag>proto</sgmltag> tag is parsed to extract the return type, the function name and the argument list. The function name in the prototype has to match the name attribute given in the <sgmltag>function</sgmltag>. </para> <para> Valid types to be used for arguments and the return type are: <simplelist> <member><type>bool</type></member> <member><type>int</type></member> <member><type>float</type></member> <member><type>string</type></member> <member><type>array</type></member> <member><type>object</type></member> <member><type>mixed</type></member> <member><type>callback</type></member> <member><type>resource</type> <emphasis>[typename]</emphasis></member> <member><type>stream</type></member> </simplelist> Argument names in prototypes are not prepended by a <literal>$</literal> sign by convention. </para> <para> Function documentation should be given using the <sgmltag>summary</sgmltag> tag for a one line description and the <sgmltag>description</sgmltag> tag for a more detailed description. Both are copied to the generated DocBook XML documentation for that function. Within <sgmltag>description</sgmltag> DocBook tags may be used. Be aware though that while <command>pecl-gen</command> accepts this validating XML parsers may complain when reading/validating an extension specification file. </para> <para> Skeleton code for parameter parsing and result passing is generated if no <sgmltag>code</sgmltag> fragment is specified for a function. A <sgmltag>code</sgmltag> section is inserted right after the generated parameter parsing code. Setting a return value is up to the code fragment if any is given, adding a template doesn't make sense in this case. </para> <!-- TODO: this is a very big TODO!!!! --> <note> <para> Maybe some stuff regarding actual coding should be added here? </para> </note> </section> <section> <title>Internal functions</title> <para> The definition of an internal function requires just the <literal>role="internal"</literal> and <literal>name=...</literal> attributes. The name can only be one of the following: <variablelist> <varlistentry> <term><literal>MINIT</literal></term> <listitem> <simpara> The module initialization function. This is called once at startup of a PHP server module or standalone (CLI or CGI) binary. </simpara> <example> <title><literal>MINIT()</literal></title> <programlisting role="xml">.... &lt;function role="internal" name="MINIT"> &lt;code> &lt;![CDATA[ int dummy = 42; dummy = dummy; ]]&gt; &lt;/code> &lt;/function>.... </programlisting> </example> </listitem> </varlistentry> <varlistentry> <term><literal>MSHUTDOWN</literal></term> <listitem> <simpara> The module shutdown function. This is called once when the PHP server module or standalone binary is properly terminated. It may not be called on program crashes or other critical errors. </simpara> </listitem> </varlistentry> <varlistentry> <term><literal>RINIT</literal></term> <listitem> <simpara> The request shutdown function. This is called by PHP server modules before actually executing a PHP script request or once right after <literal>MINIT()</literal> for standalone binaries (CGI or CLI). </simpara> </listitem> </varlistentry> <varlistentry> <term><literal>RSHUTDOWN</literal></term> <listitem> <simpara> The request shutdown function. This is called by PHP server modules after execution of PHP code has been finished or terminated. Is called even if critical PHP errors occurred but you can not rely on it being called on critical errors or crashes on the C level. </simpara> </listitem> </varlistentry> <varlistentry> <term><literal>MINFO</literal></term> <listitem> <simpara> The <literal>phpinfo()</literal> handler for this extension. It will be called whenever <literal>phpinfo()</literal> is invoked or when a standalone PHP binary is called with the <literal>-i</literal> command line option. </simpara> <simpara> The default code generated when no <sgmltag>code</sgmltag> section is given includes the extension name, summary line and release version and date, the optional logo image if specified, and the global and actual values of all <literal>php.ini</literal> directives specified. </simpara> <example> <title><literal>MINFO()</literal></title> <programlisting>.... &lt;function role='internal' name='MINFO'> &lt;code> &lt;![CDATA[ php_info_print_table_start(); php_info_print_table_header(2, "test", "table"); php_info_print_table_end(); ]]&gt; &lt;/code> &lt;/function>.... </programlisting> </example> </listitem> </varlistentry> </variablelist> </para> <para> <sgmltag>code</sgmltag> sections for the internal functions may be written as if they were C function bodies, including local variable definitions. </para> </section> <!-- deprecated <section> <title>Private functions</title> <para> The definition of a private function requires just the <literal>role="private"</literal> and <literal>name=...</literal> attributes. The complete C code of the actual function has to be put into a <sgmltag>code</sgmltag>. Private functions should be declared <literal>static</literal> and their name should of course match the name attribute, but this is not checked for. </para> </section> --> </section> <section> <title>Constants</title> <para> PHP constants are defined using <sgmltag>constant</sgmltag> tags within the <sgmltag>constants</sgmltag> environment. </para> <para> The actual constant name, type and value are specified using the <literal>name=...</literal>, <literal>type=...</literal> and <literal>value=...</literal> attributes. The constant name has to be a valid C name. PHP constant names should use uppercase letters only by convention. Possible types are "string", "int" and "float", the possible values depend on the type. For "int" and "float" you may use either numeric strings or the names of C constants (either true ANSI C/C++ constants or values <literal>#define</literal>d using the C preprocessor. "string" values are always used "as is", no constants may be used here. </para> <para> It is sufficient to specify a constant <literal>name</literal> only if a C integer constant should be available under the same name in PHP, too. </para> <para> A descriptive text may be given as content of the <sgmltag>constant</sgmltag> tag. This text will be used when generation the DocBook XML documentation. </para> <example> <title>PHP Constants</title> <programlisting role="xml"> <![CDATA[.... <constants> <constant name="SAMPLE_INT" type="int" value="42"> A sample integer constant. </constant> <constant name="SAMPLE_FLOAT" type="float" value="3.14"> A sample floating point constant. </constant> <constant name="SAMPLE_FLOAT" type="float" value="M_PI"> A sample floating point constant using a #defined constant </constant> <constant name="SAMPLE_STRING" type="string" value="Hello World!"> A sample string constant. </constant> <constant name="MY_CONST"> A shortcat for #defined integer constants </constant> </constants>.... ]]> </programlisting> </example> </section> <section> <title><literal>php.ini</literal> parameters and internal variables</title> <para> An extension may define variables that are global to either the complete extension or to a specific request. True globals that are global to the complete extensions do not need any registration so they can be defined using C code within the global <sgmltag>code</sgmltag> tag. </para> <para> Module globals that are only global to a single request need to be managed to ensure thread safety and initialization on request initialization. <literal>php.ini</literal> directive values are also stored as module globals but need some additional definitions. </para> <para> All global definitions have to be put into a <sgmltag>globals</sgmltag> environment. Simple module globals are defined using the <sgmltag>global</sgmltag> tag. <literal>php.ini</literal> directives are defined using the <sgmltag>phpini</sgmltag> tag. </para> <para> A <sgmltag>global</sgmltag> definition requires the <literal>name=...</literal> and <literal>type=...</literal> attributes to be set as valid C names and types. Which C types are allowed depends on what type definitions have been included from header files. The available types are not known when <literal>pecl-gen</literal> parses the XML specification so that types are only checked for valid name format here. Specifying a type that is not a basic C type or defined in any included file will lead to error messages when compiling the generated extension code later. </para> <para> Initial values may be specified using the <literal>value=...</literal> attribute. This feature should only be used for simple numeric values, anything more complex should better be initialized within the extensions <literal>RINIT()</literal> function. </para> <para> <literal>php.ini</literal> directives may be defined using the <sgmltag>phpini</sgmltag> within a <sgmltag>globals</sgmltag> environment. To define a <literal>php.ini</literal> directive you have to specify its name, type and default value using the <literal>name=...</literal>, <literal>type=...</literal> and <literal>value=...</literal> attributes. </para> <para> Valid directive names are C variable names. The actual directive name is the extension name followed by a single dot '<literal>.</literal>' and the specified name. Valid directive types are <type>bool</type>, <type>int</type>, <type>float</type> and <type>string</type>. </para> <para> Directive default values are passed to the engine as strings, so you may not use any C constants or preprocessor macros here. The default value strings are parsed by the <literal>OnUpdate</literal> handler registered for that directive. No value checking takes place during extension code generation or compilation, this is done by the registered <literal>OnUpdate</literal> handler at runtime during request initialization. The <literal>OnUpdate</literal> handler defaults to the appropriate internal <literal>OnUpdate</literal><emphasis>type</emphasis> handler unless you specify a different handler using the <literal>onupdate=...</literal> attribute. </para> <para> The directive value may be changed at any time unless you specify an <literal>access=...</literal> attribute. Possible values are: <variablelist> <varlistentry> <term>system</term> <listitem> <para> may only be set globally in <literal>php.ini</literal> or the web server configuration </para> </listitem> </varlistentry> <varlistentry> <term>perdir</term> <listitem><para> may be changed in local <literal>.htaccess</literal> files </para></listitem> </varlistentry> <varlistentry> <term>user</term> <listitem><para>may be changed by PHP code</para></listitem> </varlistentry> <varlistentry> <term>all</term> <listitem><para>may be changed by anyone at any time</para></listitem> </varlistentry> </variablelist> </para> <para> The content data of <sgmltag>phpini</sgmltag> tags is used to generate documentation for the defined directive. <sgmltag>global</sgmltag> definitions may also include content data but it is for internal documentation only, it is not used in DocBook XML generation (yet). </para> <example> <title>Globals</title> <programlisting role="xml"> <![CDATA[.... <globals> <global name="sample_int" type="int" value="42" /> <global name="sample_float" type="float" value="3.14" /> <global name="SAMPLE_STRING" type="char *" /> <phpini name="my_int" type="int" value="42" onupdate="OnUpdateLong" access="all"> Definition for directive "sample.my_int" </phpini> </globals>.... ]]> </programlisting> </example> <para> Access to the modul globals and ini parameters is provided in a thread safe manner through the EXTNAME_G() macro (replace EXTNAME with the upper cased name of your extension). </para> <example> <title>Globals</title> <programlisting role="xml"> <![CDATA[ <extension name="foobar"> ... <globals> <global name="sample_int" type="int" value="42" /> </globals> ... <function ...> ... <code> ... int foo = FOOBAR_G(sample_int); // get global value ... FOOBAR_G(sample_init) = 42; // set global value ... </code> </function> ]]> </programlisting> </example> <!-- TODO: add an example how to write an OnUpdate handler? --> </section> <section> <title>Resources</title> <para> You may define PHP resource types within a <sgmltag>resources</sgmltag> environment. For each <sgmltag>resource</sgmltag> you have to specify the <literal>name=...</literal> and <literal>payload=...</literal> attributes. The <literal>name</literal> has to be a valid C name and the <literal>payload</literal> has to be a valid C type specifier. The payload type can only be checked for the correctness of its form as the actual type definitions from included header files are not known to the extension generator when it generates the extension code. </para> <para> The actual resource data structure carries a pointer to the payload type. You may specify that PHP shall allocate and free the actual payload by setting the <literal>alloc=...</literal> attribute to "<literal>yes</literal>". If the payload is allocated by a library function or by yourself you should set <literal>alloc=...</literal> to "<literal>no</literal>" (the default value). </para> <para> Resources are destructed when the last variable reference refering to them is unset or at request shutdown. If your resource payload needs to be cleaned up as well you have to add an appropriate C code snippet that takes care of this using the <sgmltag>destruct</sgmltag> tag. Within the destructor snippet you may refer to the allocated payload using the <literal>resource</literal> pointer variable. </para> <para> You don't need to take care of destruction yourself if your resource payload is allocated by PHP (<literal>alloc="yes"</literal>) and needs no further cleanup work besides releasing the allocated memory. </para> <example> <title>Resources</title> <programlisting role="xml"> <![CDATA[.... <resources> <resource name="sample_resource" payload="float" alloc="yes"> <description> A simple floating point resource </description> <!-- no <destruct> needed due to the alloc attribute --> </resource> <resource name="sample_struct" payload="struct foobar" alloc="no"> <description> A foobar resource managed by an external foobar lib. </description> <destruct> foobar_release(resource); </destruct> </resource> </resources>.... ]]> </programlisting> </example> <section> <title>Resource creation and destruction</title> <para> The creation of resource instances is not defined within <sgmltag>resource</sgmltag>. This is a task to be handled by public PHP functions instead. </para> <example> <title>Resource creation</title> <screen> <![CDATA[ <function name="foo_open"> <proto>resource foo foo_open(string path)</proto> <code> return_res = foo_open(path); if (!return_res) RETURN_FALSE; </code> </function> ]]> </screen> </example> <para> Resources are freed by simply removing them from the resource list that they are in. The resources destructor function is automaticly called on list removal. </para> <example> <title>Resource destruction</title> <screen> <![CDATA[ <function name="foo_close"> <proto>void foo_close(resource foo foores)</proto> <code> zend_list_delete(Z_LVAL_P(foores)); </code> </function> ]]> </screen> </example> </section> </section> <section> <title>Classes</title> <para> OO support is planned for a future release but not implemented yet. OO code generation may be limited to PHP 5 extensions as unlike the rest of the extension API the OO implementation changed a lot between PHP 4 and 5. </para> </section> <section> <title>Streams</title> <para> Stream filter and wrapper support is experimental and not yet added to the released code base. </para> </section> <section> <title>config.m4 fragments</title> <para> Additional configure checks can be added to the generated config.m4 file used by Unix/Cygwin builds using the <sgmltag>configm4</sgmltag> tag. Using the 'position' attribute it is possible to specify whether the additional code is to be added at the top or bottom of the config.m4 file. </para> <example> <title>config.m4 additions</title> <screen> <![CDATA[ <configm4> AC_CHECK_PROG(RE2C, re2c, re2c) PHP_SUBST(RE2C) </configm4> ]]> </screen> </example> </section> <section> <title>Makefile fragments</title> <para> Makefile rules may be added using the <sgmltag>makefile</sgmltag> for Unix/Cygwin builds. Using this it is possible to add dependencies or build rules in addition to the default and auto generated rules. </para> <example> <title>Makefile fragments</title> <screen> <![CDATA[ <makefile> $(builddir)/scanner.c: $(srcdir)/scanner.re $(RE2C) $(srcdir)/scanner.re > $@ </makefile> ]]> </screen> </example> </section> <section> <title>Tests</title> <para> For now <literal>PECL_Gen</literal> generates one test case skeleton for every function prototype. </para> <para> Support for customizable test script generation is planned for a future release. </para> </section> </chapter> <chapter> <title>XML input parsing</title> <section> <title>Includes</title> <para> The XML parser used by <literal>PECL_Gen</literal> supports inclusion of additional source files using three different ways: <itemizedlist> <listitem><simpara>external entities</simpara></listitem> <listitem><simpara>a subset of XInclude</simpara></listitem> <listitem><simpara>the <literal>source</literal> attribute of <sgmltag>code</sgmltag> tags</simpara></listitem> </itemizedlist> </para> <section> <title>External entities</title> <para> ... </para> </section> <section> <title>XInclude</title> <para> ... </para> </section> <section> <title><sgmltag>code</sgmltag> tags</title> <para> ... </para> </section> </section> <section> <title>Verbatim text data</title> <para> ... </para> </section> </chapter> </book> <!-- Keep this comment at the end of the file Local variables: mode: sgml sgml-omittag:t sgml-shorttag:t sgml-minimize-attributes:nil sgml-always-quote-attributes:t sgml-indent-step:1 sgml-indent-data:t indent-tabs-mode:nil sgml-parent-document:nil sgml-default-dtd-file:"manual.ced" sgml-exposed-tags:nil sgml-local-catalogs:nil sgml-local-ecat-files:nil End: --> http://cvs.php.net/co.php/pear/CodeGen_PECL/package.xml?r=1.1&p=1 Index: pear/CodeGen_PECL/package.xml +++ pear/CodeGen_PECL/package.xml <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0"> <package> <name>CodeGen_PECL</name> <summary>Tool to generate PECL extensions from an XML description</summary> <status>beta</status> <maintainers> <maintainer> <user>hholzgra</user> <name>Hartmut Holzgraefe</name> <email>hartmut@php.net</email> <role>lead</role> </maintainer> <maintainer> <user>rasmus</user> <name>Rasmus Lerdorf</name> <email>rasmus@php.net</email> <role>contributor</role> </maintainer> <maintainer> <user>pajoye</user> <name>Pierre-Alain Joye</name> <email>pajoye@php.net</email> <role>helper</role> </maintainer> <maintainer> <user>hartmann</user> <name>Johann Peter Hartmann</name> <email>hartmann@php.net</email> <role>helper</role> </maintainer> </maintainers> <description> PECL_Gen (formerly known as ext_skel_ng) is a pure PHP replacement for the ext_skel shell script that comes with the PHP 4 source. It reads in configuration options, function prototypes and code fragments from an XML description file and generates a complete ready-to-compile PECL extension. </description> <license>PHP</license> <release> <state>beta</state> <version>0.9.0rc5</version> <date>2005-06-10</date> <notes> <![CDATA[ - implemeted new proto parser, activate with --experimental ]]> </notes> <deps> <dep type="php" rel="ge" version="5"/> <dep type="pkg" rel="ge" version="0.1">CodeGen</dep> </deps> <filelist> <file role="doc" name="manual.html"/> <dir name="/" baseinstalldir="/"> <file role="script" name="pecl-gen"> <replace from="/usr/local/bin" to="PHP_BINDIR" type="php-const" /> <replace from="@php_dir@" to="php_dir" type="pear-config" /> </file> </dir> <dir name="/" baseinstalldir="CodeGen/PECL"> <file role="php">Extension.php</file> <file role="php">Release.php</file> <file role="php">Maintainer.php</file> <file role="php">Element.php</file> <file role="php">Command.php</file> <dir name="Element"> <file role="php">Constant.php</file> <file role="php">Function.php</file> <file role="php">Global.php</file> <file role="php">Ini.php</file> <file role="php">Logo.php</file> <file role="php">Resource.php</file> <file role="php">Test.php</file> <file role="php">Class.php</file> <file role="php">Method.php</file> <file role="php">Property.php</file> <file role="php">Stream.php</file> </dir> <dir name="Dependency"> <file role="php">With.php</file> <file role="php">Lib.php</file> <file role="php">Header.php</file> </dir> <file role="php">ExtensionParser.php</file> </dir> </filelist> </release> <changelog> <release> <state>beta</state> <version>0.8.5</version> <date>2004-11-11</date> <notes> <![CDATA[ - fixed method renaming inconsistencies introduced with 0.8.4 - config.m4 additions can now be placed at 'top' or 'bottom' of config.m4 - '--force' does not remove the target directory anymore - '#include <php.h>' moved out of #ifdef block to allow static builds - 'extern "C"' specifications added on C++ builds - container tags like <functions> or <globals> are now optional - pecl-gen will now set exit status on errors ]]> </notes> </release> <release> <state>beta</state> <version>0.8.4</version> <date>2004-05-16</date> <notes> This is the first release living in PECL insteat of PEAR. Technical changes are: - improved PECL CS compliance of generated code - generated config.m4 supports both shared and static build - code snippets may be read from files instead of beeing embedded in CDATA sections - improved resource parameter handling - shortcuts for constants that just mimic C constants - global 'code' tag finally works as documented - files can be added using 'file' tag in 'deps' - ... </notes> </release> <release> <state>beta</state> <version>0.8.3</version> <date>2004-04-01</date> <notes> - this release was completely broken for unknown reasons, might be realted to the move from PEAR to PECL ...? </notes> </release> <release> <state>beta</state> <version>0.8.2</version> <date>2003-10-13</date> <notes> - fixed a bug in the parser that rendered 0.8.1 almost useless :( </notes> </release> <release> <state>beta</state> <version>0.8.1</version> <date>2003-10-12</date> <notes> - custom test generation added - minor DTD changes - code reformatted for better PEAR coding standards compliance - additional tools for whitespace and indentation management </notes> </release> <release> <state>beta</state> <version>0.8.0</version> <date>2003-07-13</date> <notes> - added documentation - check for reserved words - check for duplicate names - config,m4 header files check added - config.m4 support for makefile fragments </notes> </release> <release> <state>beta</state> <version>0.7.0</version> <date>2003-07-03</date> <notes> - a README file is written containing information on how to continue after an extension was generated - --function="proto" writes function stub to stdout - --stubs=filename now supported in ext_skel BC mode - added --help and --version options - added a short feedback howto message (can be disabled using --quiet) - --with-xml works again (ext_skel compatibility) - will now only purge and overwrite existing target directory if '--force' is requested on cmd line - .cvsignore created with platform-specific entries - PEARifying error reporting finished </notes> </release> <release> <state>beta</state> <version>0.6.1</version> <date>2003-06-29</date> <notes> typo fix in package.xml dependencies entry for XML_Parser </notes> </release> <release> <state>beta</state> <version>0.6.0</version> <date>2003-06-28</date> <notes> Moved from php5/scripts to PEAR. </notes> </release> </changelog> </package> http://cvs.php.net/co.php/pear/CodeGen_PECL/Dependency/Header.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Dependency/Header.php +++ pear/CodeGen_PECL/Dependency/Header.php <?php /** * Class representing a header file dependency * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Header.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ require_once "CodeGen/PECL/Element.php"; /** * Class representing a header file dependencyp * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Dependency_Header extends CodeGen_Element { private $name; private $prepend = false; private $path = "include"; function __construct($name) { // TODO check name $this->name = $name; } function getName() { return $this->name; } function setPrepend($prepend) { $this->prepend = ($prepend === "yes"); } function setPath($path) { $this->path = $path; } function getPath() { return $this->path; } function hCode($prepend=false) { if ($this->prepend != $prepend) { return ""; } return "#include <{$this->name}>\n"; } function configm4($extname, $withname) { $upname = strtoupper($extname); return " AC_CHECK_HEADER([\$PHP_{$upname}_DIR/{$this->path}/{$this->name}], [], AC_MSG_ERROR('{$this->name}' header not found))\n"; } function configw32($extname, $withname) { $upname = strtoupper($extname); echo " if (!CHECK_HEADER_ADD_INCLUDE(\"{$this->name}\", \"CFLAGS_$upname\")) { ERROR(\"{$extname}: header '{$this->name}' not found\"); } "; } } ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/Dependency/Lib.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Dependency/Lib.php +++ pear/CodeGen_PECL/Dependency/Lib.php <?php /** * Class representing a library dependency * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Lib.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ require_once "CodeGen/PECL/Element.php"; /** * Class representing a library dependencyp * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Dependency_Lib extends CodeGen_Element { private $name; private $path = "lib"; private $platform; private $function = false; function __construct($name, $platform = "all") { // TODO check name $this->name = $name; $this->platform = new CodeGen_Tools_Platform($platform); } function setPath($path) { $this->path = $path; } function setFunction($function) { $this->function = $function; } function getName() { return $this->name; } function configm4($extName, $withName) { static $first = true; $extUpname = strtoupper($extName); $withUpname = strtoupper($withName); if (!$this->platform->test("unix")) { return ""; } $ret = ""; if ($first) { $ret.= " PHP_SUBST({$extUpname}_SHARED_LIBADD)\n\n"; $first = false; } $ret.= " PHP_ADD_LIBRARY_WITH_PATH({$this->name}, \$PHP_{$withUpname}_DIR/{$this->path}, {$extUpname}_SHARED_LIBADD)\n"; if ($this->function) { $ret.= " AC_CHECK_LIB({$this->name}, {$this->function}, [AC_DEFINE(HAVE_{$this->upname},1,[ ])], [AC_MSG_ERROR({$this->name} library not found or wrong version)],)\n"; } return $ret; } function configw32($extName, $withName) { if (!$this->platform->test("windows")) { return ""; } $extUpname = strtoupper($extname); return " if (!CHECK_LIB(\"{$this->name}.lib\", \"{$extName}\", PHP_$extUpname)) { ERROR(\"{$extName}: library '{$this->name}' not found\"); } "; } } ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/Dependency/With.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Dependency/With.php +++ pear/CodeGen_PECL/Dependency/With.php <?php /** * Class representing a --with configure option * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: With.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ require_once "CodeGen/PECL/Element.php"; /** * Class representing a --with configure option * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Dependency_With extends CodeGen_Element { /** * Set option name * * @var name * @access private */ var $name = false; /** * Short Summary * * @var string * @access private */ var $summary = ""; /** * Long Description * * @var string * @access private */ var $description = ""; /** * A file to test for to check a given argument path * * @var string * @access private */ var $testfile = false; /** * Default search path * * @var string * @access private */ var $defaults = "/usr:/usr/local"; /** * dependant libraries * * @var string * @access private */ var $libs = array(); /** * dependant header files * * @var string * @access private */ var $headers = array(); function setName($name) { if (!ereg("[:alpha:][[:alnum:]-]*", $name)) { return PEAR::raiseError("'$name' is not a valid --with option name"); } $this->name = $name; return true; } function setSummary($text) { $this->summary = $text; return true; } function setDescription($text) { $this->description = $text; return true; } function setTestfile($path) { $this->testfile = $path; } function setDefaults($defaults) { $this->defaults = $defaults; } function addLib($lib) { $name = $lib->getName(); if (isset($this->libs[$name])) { return PEAR::raiseError("library '$name' specified twice"); } $this->libs[$name] = $lib; return true; } function addHeader($header) { $name = $header->getName(); if (isset($this->headers[$name])) { return PEAR::raiseError("header '$name' specified twice"); } $this->headers[$name] = $header; return true; } } ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/Element/Class.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Element/Class.php +++ pear/CodeGen_PECL/Element/Class.php <?php /** * Class describing a PHP class within a PECL extension * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Class.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ /** * includes */ require_once "CodeGen/PECL/Element.php"; require_once "CodeGen/PECL/Element/Property.php"; require_once "CodeGen/PECL/Element/Method.php"; require_once "CodeGen/Tools/Indent.php"; /** * Class describing a PHP class within a PECL extension * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Element_Class extends CodeGen_PECL_Element { /** * The class name * * @var string */ private $name = "unknown"; function setName($name) { if (!self::isName($name)) { return PEAR::raiseError("'$name' is not a valid class name"); } $this->name = $name; return true; } function getName() { return $this->name; } /** * A short description * * @var string */ private $summary = ""; function setSummary($text) { $this->summary = $text; return true; } /** * A long description * * @var string */ private $description = ""; function setDescription($text) { $this->description = $text; return true; } /** * Documentation * * TODO: isn't this in Element base class already? * * @var string */ private $documentation = ""; function setDocumentation($text) { $this->documentation = $text; } /** * Extents which class? * * @var string */ private $extends = ""; function setExtends($parent) { if (!self::isName($parent)) { return PEAR::raiseError("'$parent' is not a valid parent class name"); } $this->extends = $parent; } /** * Implemented Interfaces * * @var array */ private $implements = array(); function addInterface($interface) { if (!self::isName($parent)) { return PEAR::raiseError("'$interface' is not a valid interface name"); } if (isset($this->implements[$interface])) { return PEAR::raiseError("interface '$interface' added twice"); } $this->implements[$interface] = $interface; } /** * Properties * * @var array */ private $properties = array(); function addProperty($property) { if (!is_a($property, "CodeGen_PECL_Element_Property")) { return PEAR::raiseError("argument is not CodeGen_PECL_Element_Property"); } if (isset($this->properties[$property->getName()])) { return PEAR::raiseError("property '$property' already exists"); } $this->properties[$property->getName()] = $property; } /** * Member Functions * * @var array */ public $methods = array(); function addMethod($method) { if (!is_a($method, "CodeGen_PECL_Element_Method")) { return PEAR::raiseError("argument is not CodeGen_PECL_Element_Method"); } if (isset($this->functions[$method->name])) { return PEAR::raiseError("method '$function' already exists"); } $this->methods[$method->name] = $method; return true; } /** * Is this an abstract class? * * @var bool */ private $isAbstract = false; function isAbstract() { $this->isAbstract = true; } /** * Is this an interface? * * @var bool */ private $isInterface = false; function isInterface() { // TODO: check for already added non-abstract stuff $this->isInterface = true; } /** * Generate global scope code * * @access public * @return string */ function globalCode($extension) { $code = "static zend_class_entry * {$this->name}_ce_ptr = NULL;\n\n"; foreach ($this->methods as $method) { $code .= $method->cCode($extension); $code .= "\n"; } $code.= "static zend_function_entry {$this->name}_methods[] = {\n"; foreach ($this->methods as $method) { $code .= " ".$method->methodEntry()."\n"; } $code.= " { NULL, NULL, NULL }\n"; $code.="};\n"; $code.=" static void class_init_{$this->name}(void) { zend_class_entry ce; INIT_CLASS_ENTRY(ce, \"{$this->name}\", {$this->name}_methods); {$this->name}_ce_ptr = zend_register_internal_class(&ce); "; foreach ($this->properties as $property) { $code .= " ".$property->minit_code($this->name."_ce_ptr"); } $code.= "}\n"; return $code; } /** * MINIT code fragment * * @access public * @return string */ function minitCode($extension) { return "class_init_{$this->name}();\n"; } /** * DocBook documentation fragment * * @access public * @return string */ function docEntry($base) { $xml = ""; return $xml; } } ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/Element/Constant.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Element/Constant.php +++ pear/CodeGen_PECL/Element/Constant.php <?php /** * Class describing a PHP constant within a PECL extension * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Constant.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ /** * includes */ require_once "CodeGen/PECL/Element.php"; /** * Class describing a PHP constant within a PECL extension * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Element_Constant extends CodeGen_PECL_Element { /** * The constants name * * @access private * @var string */ var $name; /** * The constants PHP data type * * @access private * @var string */ var $type = "string"; /** * The constants value * * @access private * @var string */ var $value; /** * The constants description text * * @access private * @var string */ var $desc; /** * Create a C #define for this constant * * @access private * @var bool */ var $define = false; /** * Set constant name * * @access public * @param string the name * @return bool true on success */ function setName($name) { if (!self::isName($name)) { return PEAR::raiseError("'$name'is not a valid constant name"); } if (self::isKeyword($name)) { return PEAR::raiseError("'$name' is a reserved word which is not valid for constant names"); } $this->name = $name; return true; } /** * Set constant name * * @access public * @param string the type * @return bool true on success */ function setType($type) { if (!in_array($type, array('int', 'float', 'string'))) { return PEAR::raiseError("'$type' is not a valid constant type, only int, float and string"); } $this->type = $type; return true; } /** * Set constant value * * @access public * @param string the value * @return bool true on success */ function setValue($value) { $this->value = $value; if ($this->value == $this->name) { $this->deinfe = false; } return true; } /** * Set constant descriptive text * * @access public * @param string the name * @return bool true on success */ function setDesc($desc) { $this->desc = $desc; return true; } /** * Set define flag * * @access public * @param string the value * @return bool true on success */ function setDefine($value) { if (is_bool($value)) { $this->define = $value; return true; } else if (in_array($value, array("yes", "no"), true)) { $this->define = ($value === 'yes'); return true; } return PEAR::raiseError("'define' attribute has to be 'yes' or 'no', '$value' given"); } /** * Create C code snippet to register this constant * * @access public * @param class Extension extension we are owned by * @return sting C code snippet */ function cCode($extension) { switch ($this->type) { case "int": return "REGISTER_LONG_CONSTANT(\"{$this->name}\", {$this->value}, CONST_PERSISTENT | CONST_CS);\n"; case "float": return "REGISTER_DOUBLE_CONSTANT(\"{$this->name}\", {$this->value}, CONST_PERSISTENT | CONST_CS);\n"; case "string": return "REGISTER_STRING_CONSTANT(\"{$this->name}\", \"$value\", ".strlen($this->value).", CONST_PERSISTENT | CONST_CS);\n"; } } /** * Create C header snippet to register this constant * * @access public * @param class Extension extension we are owned by * @return sting C code snippet */ function hCode($extension) { if ($this->define) { switch ($this->type) { case "int": case "float": return "#define {$this->name} {$this->value}\n"; case "string": return "#define {$this->name} \"$value\"\n"; } } return ""; } /** * Generate DocBook XML section block header * * @access public * @param string Extension name * @return string DocBook XML snippet */ static function docHeader($name) { return " <table> <title>$name constants</title> <tgroup cols='3'> <thead> <row> <entry>name</entry> <entry>value</entry> <entry>descrpition</entry> </row> </thead> <tbody> "; } /** * Generate DocBook XML entry for this constant * * @access public * @param string Extension name (currently unused) * @return string DocBook XML snippet */ function docEntry($base) { return trim(" <row> <entry> <constant id='constant".strtolower(str_replace("_","-",$this->name))."'>{$this->name}</constant> (<link linkend='language.types.integer'>integer</link>) </entry> <entry>{$this->value}</entry> <entry>{$this->desc}</entry> </row> ")."\n"; } /** * Generate DocBook XML section block footer * * @access public * @param string Extension name * @return string DocBook XML snippet */ static function docFooter() { return " </tbody> </tgroup> </table> "; } } ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/Element/Function.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Element/Function.php +++ pear/CodeGen_PECL/Element/Function.php <?php /** * Class describing a function within a PECL extension * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Function.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ /** * includes */ require_once "CodeGen/PECL/Element.php"; require_once "CodeGen/Tools/Indent.php"; require_once "CodeGen/Tools/Tokenizer.php"; /** * Class describing a function within a PECL extension * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Element_Function extends CodeGen_PECL_Element { /** * The function name * * @access private * @var string */ var $name = ""; function setName($name) { if (!self::isName($name)) { return PEAR::raiseError("'$name' is not a valid function name"); } switch ($this->role) { case "internal": if (!$this->isInternalName($name)) { return PEAR::raiseError("'$name' is not a valid internal function name"); } break; case "public": // keywords are not allowed as function names if (self::isKeyword($name)) { return PEAR::raiseError("'$name' is a reserved word which is not valid for function names"); } // you should not redefine standard PHP functions foreach(get_extension_funcs("standard") as $stdfunc) { if (!strcasecmp($name, $stdfunc)) { return PEAR::raiseError("'$name' is already the name of a PHP standard function"); } } break; } $this->name = $name; return true; } function getName() { return $this->name; } /** * A short description * * @access private * @var string */ var $summary = ""; function setSummary($text) { $this->summary = $text; return true; } /** * A long description * * @access private * @var string */ var $description = ""; function setDescription($text) { $this->description = $text; return true; } /** * Type of function: internal, public * * @access private * @var string */ var $role = "public"; function setRole($role) { switch($role) { case "internal": if (!$this->isInternalName($this->name)) { return PEAR::raiseError("'{$this->name}' is not a valid internal function name"); } break; case "public": break; case "private": return PEAR::raiseError("'private' functions are no longer supported, use global <code> sections instead"); break; default: return PEAR::raiseError("'$role' is not a valid function role"); } $this->role = $role; return true; } function getRole() { return $this->role; } /** * Function has variable arguments "..." * * @access private * @var bool */ var $varargs = false; /** * Function prototype * * @access private * @var string */ var $proto = "void unknown(void)"; /** * Function returntype (parsed from proto) * * @access private * @var string */ var $returns = "void"; /** * Function parameters (parsed from proto) * * @access private * @var array */ var $params = array(); /** * Number of optional parameters (parsed from proto) * * @access private * @var int */ var $optional = 0; /** * Set parameter and return value information from PHP style prototype * * @access public * @param string PHP style prototype * @return bool Success status */ function setProto($proto, $extension) { $this->proto = $proto; if (version_compare($extension->version(), "0.9.0rc1", ">=")) { $stat = $this->newSetProto($proto, $extension); } else { $stat = $this->oldSetProto($proto); } return $stat; } /** * Set parameter and return value information from PHP style prototype * * @param string PHP style prototype * @return bool Success status */ private function newSetProto($proto, $extension) { $tokenGroups = array(); $optionals = 0; $firstOptional = 0; $squareBrackets = 0; $scanner = new CodeGen_Tools_Tokenizer($proto); // group #0 -> return type and function name $group = array(); while ($scanner->nextToken()) { if ($scanner->type === 'char' && $scanner->token === '(') { break; } $group[] = array($scanner->type, $scanner->token); } $tokenGroups[] = $group; // all following groups are parameters delimited by ',' $group = array(); while ($scanner->nextToken()) { if ($scanner->type === 'char') { if ($scanner->token === '[') { $squareBrackets++; if(!$firstOptional) { if (count($group)) { $tokenGroups[] = $group; $group = array(); } $firstOptional = count($tokenGroups); } continue; } if ($scanner->token === ',') { if (count($group)) { $tokenGroups[] = $group; $group = array(); } continue; } if ($scanner->token === ']') { $squareBrackets--; continue; } if ($scanner->token === ')') { $tokenGroups[] = $group; $group = array(); break; } } $group[] = array($scanner->type, $scanner->token); } if ($squareBrackets > 0) { return PEAR::raiseError("missing closing ']'"); } if ($squareBrackets < 0) { return PEAR::raiseError("to many closing ']'"); } // // get return type and function name // $tokens = array_shift($tokenGroups); // first the function name list($type, $token) = array_pop($tokens); if ($type !== 'char' || $token !== '@') { // @ is allowed as function name placeholder if ($type !== 'name' || !self::isName($token)) { return PEAR::raiseError("'$token' is not a valid function name"); } if (self::isKeyword($token)) { return PEAR::raiseError("keyword '$token' can't be used as function name"); } } $functionName = $token; // function name is not really used, taken from <function> tag instead // TODO: add WARNING for mismatch? if (! empty($this->name)) { $functionName = $this->name; } else { $this->name = $functionName; } // then the return type list($type, $token) = array_shift($tokens); if ($type !== 'name' || !self::isType($token)) { return PEAR::raiseError("'$token' is not a valid return type"); } $returnType = $token; // some types may carry a name if ($token === "object" || $token == "resource") { if ($tokens[0][0] === 'name') { list($type, $token) = array_shift($tokens); $returnSubtype = $token; } } // return by reference? if (count($tokens) && $tokens[0][0] === 'char' && $tokens[0][1] === '&') { list($type, $token) = array_shift($tokens); $returnByRef = true; } // any tokens left? if (count($tokens)) { return PEAR::raiseError("extra token '".$tokens[0][1]."' in function prototype"); } // // now the parameters one by one // $params = array(); $vararg = false; while ($tokens = array_shift($tokenGroups)) { if ($vararg) { return PEAR::raiseError("no further parameters are allowed after '...'"); } $param = array(); // check for default value assignment $equals = false; $default = array(); foreach ($tokens as $key => $value) { if ($value[0] === 'char' && $value[1] === '=') { $equals = $key; break; } } if ($equals !== false) { while (count($tokens) > $equals + 1) { array_unshift($default, array_pop($tokens)); } array_pop($tokens); } // get parameter name list($type, $token) = array_pop($tokens); if ($type !== 'name') { return PEAR::raiseError("'$token' is not a valid parameter name (1)"); } $param['name'] = $token; // then the parameter type list($type, $token) = array_shift($tokens); if ($type !== 'name' || !self::isType($token)) { switch ($param["name"]) { case "void": if (!empty($params)) { return PEAR::raiseError("only the first (and only) paramter can be of type void"); } $param["type"] = $param["name"]; $param["name"] = ""; break; case "...": if ($optionals) { // TODO not set yet ??? return PEAR::raiseError("'...' varargs can't be combined with optional args"); } $vararg = true; $param["type"] = $param["name"]; $param["name"] = ""; break; default: return PEAR::raiseError("'$token' is not a valid type for parameter '".$param['name']."'"); } } else { $param['type'] = $token; } if (!empty($param["name"]) && !self::isName($param["name"])) { return PEAR::raiseError("'{$param[name]}' is not a valid parameter name (2)"); } // some types may carry a name if ($token === "object" || $token === "resource") { if ($tokens[0][0] === 'name') { list($type, $token) = array_shift($tokens); $param['subtype'] = $token; } } // return by reference? if (count($tokens) && $tokens[0][0] === 'char' && $tokens[0][1] === '&') { list($type, $token) = array_shift($tokens); $param['byRef'] = true; } // any tokens left? if (count($tokens)) { return PEAR::raiseError("extra token '".$tokens[0][1]."' in specification of parameter '$parameterName'"); } // do we have a default value? switch (count($default)) { case 0: break; case 1: list($type, $token) = array_shift($default); switch ($type) { case 'string': case 'char': $param['default'] = '"'.str_replace('"', '\"', $token).'"'; break; case 'numeric': $param['default'] = $token; break; case 'name': switch (strtolower($token)) { // first check for 'known' PHP constants case 'true': case 'false': case 'null': case 'array()': $param['default'] = $token; break; default: // now see if this is a constand defined by this extension if (isset($extension->constants[$token])) { $param["default"] = $extension->constants[$token]->value; } else { return PEAR::raiseError("x1 invalid default value '$token' specification for parameter '$param[name]' ($type)"); } } break; default: return PEAR::raiseError("x2 invalid default value '$token' specification for parameter '$param[name]' ($type)"); } break; default: return PEAR::raiseError("x3 invalid default value '$token' specification for parameter '$param[name]' ($type)"); } if ($firstOptional && count($params)+1 >= $firstOptional) { $param['optional'] = true; $optionals++; } $params[] = $param; } $this->returns = $returnType; if (isset($returnSubtype)) { $this->returns .= " $returnSubtype"; } if (isset($returnByRef)) { $this->returns .= " &"; } $this->params = $params; $this->optional = $optionals; $this->vararg = $vararg; return true; } function oldSetProto($proto) { // This is the classic setProto() version, we keep it for now // as the new version is not 100% backwards compatible yet // 'tokenize' it $tokens = array(); // we collect valid C names as Strings, any other character for itself, blanks are skipped // TODO: this does no longer work if we ever add default values ... $len = strlen($proto); $name = ""; for ($n = 0; $n < $len; $n++) { $char = $proto{$n}; if (ctype_alpha($char) || $char == '_' || ($n && ctype_digit($char))) { $name .= $char; } else if ($char == '.' && $proto{$n+1} == '.' && $proto{$n+2} == '.') { $name = "..."; $n += 2; } else { if ($name) $tokens[] = $name; $name = ""; if (trim($char)) { $tokens[] = $char; } } } if ($name) { $tokens[] = $name; } $n = 0; $opts = 0; $numopts = 0; $params = array(); $returnType = ($this->isType($tokens[$n])) ? $tokens[$n++] : "void"; $functionName = $tokens[$n++]; if ($returnType === "resource" && $tokens[$n] !== "(") { $returnSubtype = $functionName; $functionName = $tokens[$n++]; } // function name is not really used, taken from <function> tag instead // TODO: add WARNING for mismatch? if (! empty($this->name)) { $functionName = $this->name; } else { $this->name = $functionName; } if ($tokens[$n++] != '(') return PEAR::raiseError("'(' expected instead of '$tokens[$n]'"); if ($tokens[$n] == ')') { /* done */ } else if ($tokens[$n] == '...') { $params[0]['type'] = "..."; $n++; } else { for ($param = 0; $tokens[$n]; $n++, $param++) { if ($tokens[$n] == '[') { $params[$param]['optional'] = true; $opts++; $n++; if ($param > 0) { if ($tokens[$n] != ',') { return PEAR::raiseError("',' expected after '[' instead of '$token[$n]'"); } $n++; } } if (!$this->isType($tokens[$n])) { return PEAR::raiseError("type name expected instead of '$tokens[$n]'"); } $params[$param]['type'] = $tokens[$n]; $n++; if ($tokens[$n] == "&") { $params[$param]['byRef'] = true; $n++; } if ($this->isName($tokens[$n])) { $params[$param]['name']=$tokens[$n]; $n++; } if ($tokens[$n] == "&") { $params[$param]['byRef'] = true; $n++; } if ($params[$param]['type'] === "resource" && $this->isName($tokens[$n])) { $params[$param]['subtype'] = $params[$param]['name']; $params[$param]['name'] = $tokens[$n]; $n++; } if ($tokens[$n] == '[') { $n--; continue; } if ($tokens[$n] == ',') continue; if ($tokens[$n] == ']') break; if ($tokens[$n] == ')') break; } $numopts = $opts; while ($tokens[$n] == ']') { $n++; $opts--; } if ($opts != 0) { return PEAR::raiseError("'[' / ']' count mismatch"); } } if ($tokens[$n] != ')') { return PEAR::raiseError("')' expected instead of '$tokens[$n]'"); } $this->returns = $returnType; if (isset($returnSubtype)) { $this->returns .= " $returnSubtype"; } $this->params = $params; $this->optional = $numopts; return true; } /** * Code snippet * * @access private * @var string */ var $code = ""; /** * Source file of code snippet * * @access private * @var string */ var $codeFile = ""; /** * Source line of code snippet * * @access private * @var int */ var $codeLine = 0; function setCode($text, $line = 0, $file = "") { $this->code = $text; $this->codeFile = $file; $this->codeLine = $line; return true; } /** * Check whether a function name is already used internally * * @access public * @param string function name * @return bool true if function name is already used internally */ function isInternalName($name) { switch ($name) { case "MINIT": case "MSHUTDOWN": case "RINIT": case "RSHUTDOWN": case "MINFO": return true; } return false; } /** * Helper for cCode * * @param string Parameter spec. array * @param string default value for type * @return string default value */ function defaultval($param, $default) { if (isset($param["default"])) { return $param["default"]; } return $default; } /** * Hook for parameter parsing API function * * @param string C expr. for number of arguments * @param string Argument string * @param array Argument variable pointers */ protected function parseParameterHook($argc, $argString, $argPointers) { return " if (zend_parse_parameters($argc TSRMLS_CC, \"$argString\", ".join(", ",$argPointers).") == FAILURE) { return; } "; } /** * Create C code implementing the PHP userlevel function * * @access public * @param class Extension extension the function is part of * @return string C code implementing the function */ function cCode($extension) { $code = ""; $returns = explode(" ", $this->returns); switch ($this->role) { case "public": // function prototype comment $code .= "\n/* {{{ proto {$this->proto}\n "; if (!empty($this->summary)) { $code .= $this->summary; } $code .= " */\n"; // function declaration $code .= $this->cProto()."\n"; $code .= "{\n"; // for functions returning a named resource we create payload pointer variable if ($returns[0] === "resource" && isset($returns[1]) && isset($extension->resources[$returns[1]])) { $resource = $extension->resources[$returns[1]]; $payload = $resource->payload; if ($resource->alloc === "yes") { $code .= " $payload * return_res = ($payload *)ecalloc(1, sizeof($payload));\n"; } else { $code .= " $payload * return_res;\n"; } } else { $code .= " void * return_res;\n"; } // now we create local variables for all parameters // at the same time we put together the parameter parsing string if (is_array($this->params) && count($this->params)) { $argString = ""; $argPointers = array(); $optional = false; $resFetch = ""; $zvalType = false; foreach ($this->params as $param) { if ($param["type"] === "void" || $param["type"] === "...") { continue; } $name = $param['name']; $argPointers[] = "&$name"; if (isset($param['optional']) && !$optional) { $optional = true; $argString .= "|"; } switch ($param['type']) { case "bool": $argString .= "b"; $default = $this->defaultval($param, "0"); $code .= " zend_bool $name = $default;\n"; break; case "int": $argString .= "l"; $default = $this->defaultval($param, "0"); $code .= " long $name = $default;\n"; break; case "float": $argString .= "d"; $default = $this->defaultval($param, "0.0"); $code .= " double $name = $default;\n"; break; case "string": $argString .= "s"; $default = $this->defaultval($param, "NULL"); $code .= " const char * $name = $default;\n"; $code .= sprintf(" int {$name}_len = %d;\n", $default==="NULL" ? 0 : strlen($default) - 2); $argPointers[] = "&{$name}_len"; break; case "array": $zvalType = true; $argString .= "a"; $code .= " zval * $name = NULL;\n"; break; case "object": $zvalType = true; $code .= " zval * $name = NULL;\n"; if (isset($param['subtype'])) { $argString .= "O"; $argPointers[] = "$param[subtype]_ce_ptr"; } else { $argString .= "o"; } break; case "resource": $zvalType = true; $argString .= "r"; $code .= " zval * $name = NULL;\n"; $code .= " int {$name}_id = -1;\n"; if (isset($param['subtype']) && isset($extension->resources[$param['subtype']])) { $resource = $extension->resources[$param['subtype']]; $varname = "res_{$name}"; $code .= " {$resource->payload} * $varname;\n"; $resFetch .= " ZEND_FETCH_RESOURCE($varname, {$resource->payload} *, &$name, {$name}_id, \"$param[subtype]\", le_$param[subtype]);\n"; } else { $resFetch .=" ZEND_FETCH_RESOURCE(???, ???, $name, {$name}_id, \"???\", ???_rsrc_id);\n"; } break; case "stream": $zvalType = true; $argString .= "r"; $code .= " zval * {$name}_zval = NULL; \n"; $code .= " php_stream * $name = NULL:\n"; $resFetch.= " php_stream_from_zval($name, &_z$name);\n"; break; case "callback": $resFetch.= " if (!zend_is_callable({$name}, 0 NULL) {\n"; $resFetch.= " php_error(E_WARNING, \"Invalid comparison function.\");\n"; $resFetch.= " return;"; $resFetch.= " }\n"; /* fallthru */ case "mixed": $zvalType = true; $argString .= "z"; $code .= " zval * {$name} = NULL;\n"; break; } if (empty($param['byRef'])) { $argString .= "/"; } else if (!$zvalType) { // TODO: pass by ref for 'simple' types requires further thinking } } } // now we do the actual parameter parsing if (empty($argString)) { if (!empty($this->params) && $this->params[0]['type'] == "...") { $code .= "/* custom parsing code required */\n\n"; } else { $code .= " if (ZEND_NUM_ARGS()>0) {\n WRONG_PARAM_COUNT;\n }\n\n"; } } else { if ($this->varargs) { $argc = sprint("MIN(ZEND_NUM_ARGS(),%d)", count($this->params)-1); } else { $argc = "ZEND_NUM_ARGS()"; } $code .= $this->parseParameterHook($argc, $argString, $argPointers); if ($this->varargs) { // TODO can't do a zend_get_parameters_array with offset yet } if ($resFetch) { $code.="$resFetch\n\n"; } } // for functions returning an array we initialize return_value if ($returns[0] === "array") { $code.="array_init(return_value);\n\n"; } if ($this->code) { if ($extension->linespecs) { // generate #line preprocessor directive if ($this->codeLine) { $linedef = "#line {$this->codeLine} "; if ($this->codeFile) { $linedef.= '"'.$this->codeFile.'"'; } } else { $linedef = ""; } } // if function code is specified so we add it here if ($extension->language == "c") { // in C variable declarations have to be at the very beginning // of a block, so we have to add {...} around the snippet $code .= " do {\n"; if (isset($linedef)) { $code .= "$linedef\n"; } $code .= CodeGen_Tools_Indent::indent(8, $this->code); $code .= " } while(0);\n"; } else { // in C++ variable may be declared at any time if (isset($linedef)) { $code .= "$linedef\n"; } $code .= CodeGen_Tools_Indent::indent(4, $this->code)."\n"; } // when a function returns a named resource we know what to do if ($returns[0] == "resource" && isset($returns[1])) { $code .= " ZEND_REGISTER_RESOURCE(return_value, return_res, le_$returns[1]);\n"; } } else { // no code snippet was given so we produce a suggestion for the return statement $code .= " php_error(E_WARNING, \"{$this->name}: not yet implemented\"); RETURN_FALSE;\n\n"; switch ($returns[0]) { case "void": break; case "bool": $code .= " RETURN_FALSE;\n"; break; case "int": $code .= " RETURN_LONG(0);\n"; break; case "float": $code .= " RETURN_DOUBLE(0.0);\n"; break; case "string": $code .= " RETURN_STRINGL(\"\", 0, 1);\n"; break; case "array": $code .= " array_init(return_value);\n"; break; case "object": $code .= " object_init(return_value)\n"; break; case "resource": if (isset($returns[1])) { $code .= " ZEND_REGISTER_RESOURCE(return_value, return_res, le_$returns[1]);\n"; } else { $code .= " /* RETURN_RESOURCE(...); */\n"; } break; case "stream": $code .= " /* php_stream_to_zval(stream, return_value); */\n"; break; case "mixed": $code .= " /* RETURN_...(...); */\n"; break; default: $code .= " /* UNKNOWN RETURN TYPE '$this->returns' */\n"; break; } } $code .= "}\n/* }}} */\n\n"; break; case "internal": if (!empty($this->code)) { $code .= " {\n"; $code .= CodeGen_Tools_Indent::indent(8, $this->code."\n"); $code .= " }\n"; } break; } return $code; } /** * Create DocBook reference entry for the function * * @access public * @param string base (currently not used) * @return string DocBook XML code */ function docEntry($base) { $xml = '<?xml version="1.0" encoding="iso-8859-1"?> <!-- '.'$'.'Revision: 1.0 $ --> <refentry id="function.' . strtolower(str_replace("_", "-", $this->name)) . '"> <refnamediv> <refname>' . $this->name . '</refname> <refpurpose>' . $this->summary . '</refpurpose> </refnamediv> <refsect1> <title>Description</title> <methodsynopsis> '; $xml .= " <type>{$this->returns}</type><methodname>{$this->name}</methodname>\n"; if (empty($this->params) || $this->params[0]["type"] === "void") { $xml .= " <void/>\n"; } else if ($this->params[0]["type"] === "...") { $xml .= " <methodparam choice='opt' rep='repeat'><type>mixed</type><parameter>...</parameter></methodparam>\n"; } else { foreach ($this->params as $key => $param) { if (isset($param['optional'])) { $xml .= " <methodparam choice='opt'>"; } else { $xml .= " <methodparam>"; } $xml .= "<type>$param[type]</type><parameter>"; if (isset($param['byRef'])) { $xml .= "&amp;"; } $xml .= "$param[name]</parameter>"; $xml .= "</methodparam>\n"; } } $description = $this->description; if (!strstr($this->description,"<para>")) { $description = " <para>\n$description </para>\n"; } $xml .= ' </methodsynopsis> '.$description.' </refsect1> </refentry> '; $xml .= $this->docEditorSettings(4); return $xml; } /** * Create test case for this function * * @access public * @param class Extension extension the function is part of * @return string PHP test script */ function writeTest($extension) { $fp = fopen("{$extension->dirpath}/tests/{$this->name}.phpt", "w"); fputs($fp, "--TEST-- {$this->name}() function --SKIPIF-- <?php if (!extension_loaded('{$extension->name}')) print 'skip'; ?> --POST-- --GET-- --FILE-- <?php echo 'no test case for {$this->name}() yet'; ?> --EXPECT-- no test case for {$this->name}() yet"); fclose($fp); } /** * C function signature * * @return string C snippet */ function cProto() { return "PHP_FUNCTION({$this->name})"; } } ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/Element/Global.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Element/Global.php +++ pear/CodeGen_PECL/Element/Global.php <?php /** * Class describing a thread-global within a PECL extension * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Global.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ /** * includes */ require_once "CodeGen/PECL/Element.php"; /** * Class describing a thread-global within a PECL extension * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Element_Global extends CodeGen_PECL_Element { // TODO add description and use it for C code comments /** * The name of the global * * @access private * @var string */ var $name; /** * Set method for name * * @access public * @var string global variable name */ function setName($name) { if (!self::isName($name)) { return PEAR::raiseError("'$name' is not a valid global name"); } $this->name = $name; return true; } /** * The type of the global * * @access private * @var string */ var $type; /** * Set method for name * * @access public * @var string C type name */ function setType($name) { if (!self::isType($name)) { return PEAR::raiseError("'$name' is not a valid type for a global"); } $this->type = $name; return true; } /** * Default value * * @access private * @var string */ var $value; /** * Set method for default value * * @access public * @param string default value */ function setValue($value) { // TODO checks $this->value = $value; return true; } /** * Overriding type check as we deal with real C types here * * @access public * @var string C type specifier */ function isType($type) { /* check is rather naive as it doesn't know about context so we check for a sequence of valid names for now TODO: check for either simple type, struct/class or single word (typedef) */ $array = explode(" ", str_replace('*',' ',$type)); foreach ($array as $name) { if (empty($name)) continue; if (!$this->isName($name)) return false; } return true; } /** * Generate header for global variable registration code * * @access private * @param string extension basename * @return string C code snippet */ static function cCodeHeader($name) { return "static void php_{$name}_init_globals(zend_{$name}_globals *{$name}_globals)\n{\n"; } /** * Generate registration code for this global variable * * @access private * @param string extension basename * @return string C code snippet */ function cCode($name) { $code = " {$name}_globals->{$this->name} = "; if (strstr($this->type, "*")) { $code .= "NULL;\n"; } else { $code .= "0;\n"; } return $code; } /** * Generate footer for global variable registration code * * @access private * @param string extension basename * @return string C code snippet */ static function cCodeFooter($name) { return ' } static void php_'.$name.'_shutdown_globals(zend_'.$name.'_globals *'.$name.'_globals) { }'; } /** * Generate header for global variable registration code in header file * * @access private * @param string extension basename * @return string C code snippet */ static function hCodeHeader($name) { return "ZEND_BEGIN_MODULE_GLOBALS({$name})\n"; } /** * Generate declaration for this global variable in header file * * @access private * @param string extension basename * @return string C code snippet */ function hCode($name) { return " {$this->type} {$this->name};\n"; } /** * Generate footer for global variable registration code in header file * * @access private * @param string extension basename * @return string C code snippet */ static function hCodeFooter($name) { $upname = strtoupper($name); return " ZEND_END_MODULE_GLOBALS({$name}) #ifdef ZTS #define {$upname}_G(v) TSRMG({$name}_globals_id, zend_{$name}_globals *, v) #else #define {$upname}_G(v) ({$name}_globals.v) #endif "; } } ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/Element/Ini.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Element/Ini.php +++ pear/CodeGen_PECL/Element/Ini.php <?php /** * Class describing a PHP ini directive within a PECL extension * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Ini.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ /** * includes */ require_once "CodeGen/PECL/Element.php"; /** * Class describing a PHP ini directive within a PECL extension * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Element_Ini extends CodeGen_PECL_Element { // TODO this should be a subclass of CodeGen_PECL_Element_Global ? /** * Directive name * * @access private * @var string */ var $name; /** * Set method for name * * @access public * @var string directive name */ function setName($name) { if (!self::isName($name)) { return PEAR::raiseError("'$name' is not a valid php.ini directive name"); } $this->name = $name; return true; } /** * Directive data type * * @access private * @var string */ var $type; /** * Set method for data type * * @access public * @param string one of bool, int, float, string */ function setType($type) { switch ($type) { case "bool": $this->onupdate = "OnUpdateBool"; $this->cType = "zend_bool"; return true; case "int": $this->onupdate = "OnUpdateLong"; $this->cType = "long"; return true; case "float": $this->onupdate = "OnUpdateReal"; $this->cType = "double"; return true; case "string": $this->onupdate = "OnUpdateString"; $this->cType = "char *"; return true; default: return PEAR::raiseError("'$this->type' not supported, only bool, int, float and string"); } } /** * Directive default value * * @access private * @var string */ var $value; /** * Set method for default value * * @access public * @param string default value */ function setValue($value) { // TODO checks $this->value = $value; return true; } /** * Directive description * * @access private * @var string */ var $desc; /** * Set method for directive description * * @access public * @param string description */ function setDesc($desc) { $this->desc = $desc; return true; } /** * Directive access mode * * @access private * @var string */ var $access = "PHP_INI_ALL"; /** * Set method for access mode * * @access private * @param string access mode specification (system|perdir|user|all) */ function setAccess($access) { switch ($access) { case "system": $this->access = "PHP_INI_SYSTEM"; return true; case "perdir": $this->access = "PHP_INI_PERDIR"; return true; case "user": // TODO shouldn't this be ALL instead? $this->access = "PHP_INI_USER"; return true; case "all": case "": $this->access = "PHP_INI_ALL"; return true; default: return PEAR::raiseError("'$access' is not a valid access mode (system|perdir|user|all)"); } } /** * Directive OnUpdate handler * * @access private * @var string */ var $onupdate; /** * Set method for OnUpdate handler * * @access public * @param string C function name */ function setOnUpdate($name) { if (!self::isName($name)) { return PEAR::raiseError("'$name' is not a valid update function name"); } $this->onupdate = $name; return true; } /** * Internal C type that stores the directives value * * @access private * @var string */ var $cType; /** * Constructor */ function __construct() { $this->setType("string"); } /** * Generate header for ini directive registration code * * @access private * @param string extension basename * @return string C code snippet */ static function cCodeHeader($name) { // this is a small incompatibility between ZE1 and ZE2 APIs // "OnUpdateInt" was changed to "OnUpdateLong" as it actualy // works on C type "long", not "int" // the actual implementation didn't change so it is safe to // just revert the name change using a cpp #define // TODO: skip this for extensions that depend on PHP 5 anyway $code = " #ifndef ZEND_ENGINE_2 #define OnUpdateLong OnUpdateInt #endif "; $code .="PHP_INI_BEGIN()\n"; return $code; } /** * Generate registration code for this directive * * @access private * @param string extension basename * @return string C code snippet */ function cCode($name) { return " STD_PHP_INI_ENTRY(\"$name.{$this->name}\", \"{$this->value}\", {$this->access}, {$this->onupdate}, {$this->name}, zend_{$name}_globals, {$name}_globals)\n"; } /** * Generate footer for ini directive registration code * * @access private * @param string extension basename * @return string C code snippet */ static function cCodeFooter($name) { return "PHP_INI_END()\n\n"; } /** * Generate header for ini directive documentation * * @access private * @param string extension basename * @return string DocBook XML snippet */ static function docHeader($name) { return " <table> <title>$name runtime configuration</title> <tgroup cols='3'> <thead> <row> <entry>directive</entry> <entry>default value</entry> <entry>descrpition</entry> </row> </thead> <tbody> "; } /** * Generate documentation for ini directive documentation * * @access private * @param string id basename for extension * @return string DocBook XML snippet */ function docEntry($base) { return " <row> <entry>$this->name</entry> <entry>$this->value</entry> <entry>$this->desc</entry> </row> "; } /** * Generate footer for ini directive documentation * * @access private * @param string extension basename * @return string DocBook XML snippet */ static function docFooter() { return " </tbody> </tgroup> </table> "; } } ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/Element/Logo.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Element/Logo.php +++ pear/CodeGen_PECL/Element/Logo.php <?php /** * Class that manages internal logo images for the extensions phpinfo block * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Logo.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ /** * includes */ require_once "CodeGen/PECL/Element.php"; /** * Class that manages internal logo images for the extensions phpinfo block * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Element_Logo extends CodeGen_PECL_Element { /** * Basename * * @access private * @var string */ var $name; /** * ID for URL call of image ("...?=ID") * * @access private * @var string */ var $id; /** * The actual image data as a binary string * * @access private * @var string */ var $data; /** * * @access private * @var string */ var $mimeType = false; /** * Constructor * * @access public * @param string image basename * @param string source filename */ function __construct($name) { $this->name = $name; $this->id = '"'.strtoupper($name).'_LOGO_ID"'; } /** * Set image data and mimetype * * @param string binary image data * @param string mimetype * @return bool true on success */ function setData($data, $mimetype = false) { $this->data = $data; if ($mimetype) { $this->mimetype = $mimetype; } else { // perform a little magic // we only accept GIF, PNG and JPEG here, so we can test // for the 'magic' signatures ourself if (!strncmp("GIF8", $data, 4)) { $this->mimetype = "image/gif"; } else if(!strncmp(chr(0x89)."PNG\r\n", $data, 6)) { $this->mimetype = "image/png"; } else if(ord($data[0]) == 0xff && ord($data[1]) == 0xd8) { $this->mimetype = "image/jpeg"; } else { return PEAR::raiseError("can't detect mimetype for logo image data, pease add 'mimetype=...' attribute"); } } return true; } /** * Load image data from file, set mimetype * * @param string path to image file * @param string mimetype * @return bool true on success */ function loadFile($path, $mimetype = false) { if (!is_readable($path)) { return PEAR::raiseError("Can't read logo image file '$path'"); } return $this->setData(file_get_contents($path), $mimetype); } /** * Code snippet for image registration in MINFO() * * @access public * @return string C code snippet */ function minitCode() { return " php_register_info_logo({$this->id}, \"{$this->mimeType}\", {$this->name}_logo, ".strlen($this->data).");\n"; } /** * Code snippet for image release in MSHUTDOWN() * * @access public * @return string C code snippet */ function mshutdownCode() { return " php_unregister_info_logo({$this->id});\n"; } /** * Code snippet for image data declaration * * @access public * @param string extension name * @return string C code snippet */ function cCode($name) { return " #include \"php_logos.h\" static unsigned char {$this->name}_logo[] = { #include \"{$this->name}_logo.h\" }; "; } /** * Generate data for declaration include file * * @access public * @return string C code snippet */ function hCode() { $len = strlen($this->data); $code = " "; $i=0; for ($n = 0; $n < $len; $n++) { $code .= sprintf(" %3d",ord($this->data[$n])); if ($n == $len - 1) break; $code .= ","; if (++$i==8) { $code .= "\n "; $i=0; } } $code .= "\n"; return $code; } } ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/Element/Method.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Element/Method.php +++ pear/CodeGen_PECL/Element/Method.php <?php /** * Class that describes a member function within a PHP class * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Method.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ /** * includes */ require_once "CodeGen/PECL/Element.php"; require_once "CodeGen/PECL/Element/Function.php"; require_once "CodeGen/PECL/Element/Class.php"; /** * Class that describes a member function within a PHP class * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Element_Method extends CodeGen_PECL_Element_Function { function __construct($classname) { $this->classname = $classname; } /** * The name of the class this method belongs to * * @var string */ private $classname = ""; /** * Name for procedural alias of this method * * @var string */ private $proceduralName = ""; function getProceduralName() { return $this->proceduralName; } function setProceduralName($name) { if (!$this->isName($name)) { return PEAR::raiseError("'$name' is not a valid function alias name"); } $this->proceduralName = $name; return true; } /** * Is this an abstract method? * * @var bool */ private $isAbstract = false; function isAbstract() { $this->isAbstract = true; } /** * Is this an interface method? * * @var bool */ private $isInterface = false; function isInterface() { $this->isInterface = true; } /** * Is this a final method? * * @var bool */ private $isFinal = false; function isFinal() { $this->isFinal = true; } /** * Is this a static method? * * @var bool */ private $isStatic = false; function isStatic() { $this->isStatic = true; } /** * Visibility of this property * * @var string */ private $access = "public"; function setAccess($access) { switch ($this->access) { case "private": case "protected": case "public": $this->access = $access; return true; default: return PEAR::raiseError("'$access' is not a valid access property"); } } /** * Code needed ahead of the method table * * Abstract/Interface methods need to define their argument * list ahead of the method table * * @returns string */ function argInfoCode() { if ($this->isAbstract) { } } /** * Hook for parameter parsing API function * * @param string C expr. for number of arguments * @param string Argument string * @param array Argument variable pointers */ protected function parseParameterHook($argc, $argString, $argPointers) { return " if (zend_parse_method_parameters($argc TSRMLS_CC, getThis(), \"$argString\", ".join(", ",$argPointers).") == FAILURE) { return; } "; } /** * Set parameter and return value information from PHP style prototype * * @access public * @param string PHP style prototype * @return bool Success status */ function setProto($proto) { parent::setProto($proto); $param = array(); $param['name'] = "thisObj"; $param['type'] = "object"; $param['subtype'] = $this->classname; array_unshift($this->params, $param); } /** * Create registration line for method table * * @param string Name of class owning this method * @return string C code snippet */ function methodEntry() { $code= "PHP_ME({$this->classname}, {$this->name}, NULL, "; $code.= "ZEND_ACC_".strtoupper($this->access); if ($this->isStatic) { $code.= " | ZEND_ACC_STATIC"; } if ($this->isAbstract) { $code.= " | ZEND_ACC_ABSTRACT"; } if ($this->isInterface) { $code.= " | ZEND_ACC_INTERFACE"; } if ($this->isFinal) { $code.= " | ZEND_ACC_FINAL"; } $code.= ")"; return $code; } /** * Create proto line for method * * @param string Name of class owning this method * @return string C code snippet */ function cProto() { return "PHP_METHOD({$this->classname}, {$this->name})"; } } ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/Element/Property.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Element/Property.php +++ pear/CodeGen_PECL/Element/Property.php <?php /** * Class describing a class property within a PECL extension * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Property.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ /** * includes */ require_once "CodeGen/PECL/Element.php"; require_once "CodeGen/PECL/Element/Function.php"; require_once "CodeGen/PECL/Element/Class.php"; /** * Class describing a class property within a PECL extension * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Element_Property extends CodeGen_PECL_Element { /** * Is this an abstract property? * * @var bool */ private $isAbstract = false; function isAbstract() { $this->isAbstract = true; } /** * Is this an interface property? * * @var bool */ private $isInterface = false; function isInterface() { $this->isInterface = true; } /** * Is this a final property? * * @var bool */ private $isFinal = false; function isFinal() { $this->isFinal = true; } /** * Is this a static property? * * @var bool */ private $isStatic = false; function isStatic() { $this->isStatic = true; } /** * Visibility of this property * * @var string */ private $access = "public"; function setAccess($access) { switch ($this->access) { case "private": case "protected": case "public": $this->access = $access; return true; default: return PEAR::raiseError("'$access' is not a valid access property"); } } /** * Property type * * @var string */ private $type = "null"; function setType($type) { switch ($type) { case "void": $type = "null"; break; case "int": $type = "long"; break; case "long": // case "float": not yet supported by ZEND API // case "double": not yet supported by ZEND API case "string": case "null": break; default: return PEAR::raiseError("'$type' is not a valid property type"); } $this->type = $type; return true; } /** * Property name * * @var string */ private $name = "unknown"; function setName($name) { if (!$this->isName($name)) { return PEAR::raiseError("'$name' is not a valid property name"); } $this->name = $name; return true; } function getName() { return $this->name; } /** * Default value * * @var string * @access private */ private $value = ""; function setValue($value) { // TODO check? $this->value = $value; return true; } /** * MINIT code fragment * * @access public * @return string */ function minitCode($classptr) { $code = "zend_declare_property_{$this->type}({$classptr}, "; $code.= '"'.$this->name.'", '.strlen($this->name).', '; switch ($this->type) { case "string": $code .= '"'.$this->value.'", '; break; case "long": $code .= (int)$this->value.", "; break; // case "double": not yet supported default: break; } $code.= "ZEND_ACC_".strtoupper($this->access); if ($this->isStatic) { $code.= " | ZEND_ACC_STATIC"; } if ($this->isAbstract) { $code.= " | ZEND_ACC_ABSTRACT"; } if ($this->isInterface) { $code.= " | ZEND_ACC_INTERFACE"; } if ($this->isFinal) { $code.= " | ZEND_ACC_FINAL"; } $code .= " TSRMLS_DC);\n"; return $code; } } ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/Element/Resource.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Element/Resource.php +++ pear/CodeGen_PECL/Element/Resource.php <?php /** * Class for managing PHP internal resource types * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Resource.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ /** * includes */ require_once "CodeGen/PECL/Element.php"; /** * Class for managing PHP internal resource types * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Element_Resource extends CodeGen_PECL_Element { /** * Resource type name * * @var string * @access private */ var $name = "unknown"; /** * Set method for name * * @access public * @param string name * @return bool true on success */ function setName($name) { if (!self::isName($name)) { return PEAR::raiseError("'$name' is not a valid resource name"); } $this->name = $name; return true; } /** * Type of the payload that the resource data pointer points to * * @var string * @access private */ var $payload = "void"; /** * Set method for payload type * * @access public * @param string type name * @return bool true on success */ function setPayload($type) { $this->payload = $type; return true; } /** * Whether the resource memory is allocated and freed by the extension itself * * @var string * @access private */ var $alloc = "yes"; /** * Set method for alloc * * @access public * @param string "yes" or "no" * @return bool true on success */ function setAlloc($text) { // TODO check values $this->alloc = $text; return true; } /** * Code snippet to be added to the resource destructor callback * * @var string * @access private */ var $destruct = ""; /** * Set method for destructor snippet * * @access public * @param string C code snippet * @return bool true on success */ function setDestruct($text) { $this->destruct = $text; return true; } /** * DocBook XML snippet that describes the resource for the manual * * @var string * @access private */ var $description = ""; /** * Set method for destructor snippet * * @access public * @param string C code snippet * @return bool true on success */ function setDescription($text) { $this->description = $text; return true; } /** * Generate resource registration code for MINIT() * * @access public * @return string C code snippet */ function minitCode() { return " le_{$this->name} = zend_register_list_destructors_ex({$this->name}_dtor, NULL, \"{$this->name}\", module_number); "; } /** * Generate C code for resource destructor callback * * @access public * @param object extension * @return string C code snippet */ function cCode($extension) { $dtor = "int le_{$this->name};\n"; if ($extension->language == "cpp") { $dtor.= 'extern "C" '; } $dtor.= "void {$this->name}_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) { {$this->payload} * resource = ({$this->payload} *)(rsrc->ptr); "; $dtor .= CodeGen_Tools_Indent::indent(4, $this->destruct); if ($this->alloc === "yes") { $dtor .= "\n\tefree(resource);\n"; } $dtor .= "}\n"; return $dtor; } /** * Generate covenience macros for resource access * * @access public * @return string C code snippet */ function hCode() { $upname = strtoupper($this->name); return " #define {$upname}_REGISTER(r) ZEND_REGISTER_RESOURCE(return_value, r, le_{$this->name }); #define {$upname}_FETCH(r, z) ZEND_FETCH_RESOURCE(r, {$this->payload} *, z, -1, ${$this->name}, le_{$this->name }); if (!r) { RETURN_FALSE; } "; } /** * Generate documentation for this resource * * @access public * @param string id basename for extension * @return string DocBook XML code snippet */ function docEntry($base) { return " <section id='$base.resources.{$this->name}'> <title><literal>{$this->name}</literal></title> <para> {$this->description} </para> </section> "; } } ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/Element/Stream.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Element/Stream.php +++ pear/CodeGen_PECL/Element/Stream.php <?php /** * Class for managing PHP stream wrappers * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Stream.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ /** * includes */ require_once "CodeGen/PECL/Element.php"; /** * Class for managing PHP stream wrappers * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Element_Stream extends CodeGen_PECL_Element { /** * Stream type name * * @var string * @access private */ var $name = "unknown"; /** * Set method for name * * @access public * @param string name * @return bool true on success */ function setName($name) { if (!self::isName($name)) { return PEAR::raiseError("'$name' is not a valid stream name"); } $this->name = $name; return true; } function getName() { return $this->name; } /** * DocBook XML snippet that describes the resource for the manual * * @var string * @access private */ var $summary = ""; /** * Set method for destructor snippet * * @access public * @param string C code snippet * @return bool true on success */ function setSummary($text) { $this->summary = $text; return true; } /** * DocBook XML snippet that describes the resource for the manual * * @var string * @access private */ var $description = ""; /** * Set method for destructor snippet * * @access public * @param string C code snippet * @return bool true on success */ function setDescription($text) { $this->description = $text; return true; } var $codeBlocks = array(); function addCode($role, $code) { if (isset($codeBlock[$role])) { return PEAR::raiseError("Codeblock '$role' was already set"); } if (!in_array($role, array("open", "close", "stat", "urlstat", "diropen", "unlink", "rename", "mkdir", "rmdir", "write", "read", "flush", "seek", "cast", "set"))) { return PEAR::raiseError("'$role' is not a valid stream codeblock type"); } $this->codeBlocks[$role] = $code; } /** * Generate resource registration code for MINIT() * * @access public * @return string C code snippet */ function minitCode() { return "/* ".$this->name." stream goes here */\n"; } /** * Generate C code for resource destructor callback * * @access public * @param object extension * @return string C code snippet */ function cCode($extension) { ob_start(); echo "static php_stream_ops php_{$this->name}_stream_ops = {\n"; echo " "; echo isset($this->codeBlocks['write']) ? "php_{$this->name}_file_write," : "NULL, /* write */"; echo "\n"; echo " "; echo isset($this->codeBlocks['read']) ? "php_{$this->name}_file_read," : "NULL, /* read */"; echo "\n"; echo " "; echo isset($this->codeBlocks['close']) ? "php_{$this->name}_file_close," : "NULL, /* close */"; echo "\n"; echo " "; echo isset($this->codeBlocks['flush']) ? "php_{$this->name}_file_flush," : "NULL, /* flush */"; echo "\n"; echo '"'.$this->summary.'"'."\n"; echo " "; echo isset($this->codeBlocks['cast']) ? "php_{$this->name}_file_cast," : "NULL, /* cast */"; echo "\n"; echo " "; echo isset($this->codeBlocks['stat']) ? "php_{$this->name}_file_stat," : "NULL, /* stat */"; echo "\n"; echo " "; echo isset($this->codeBlocks['set']) ? "php_{$this->name}_file_set_option," : "NULL, /* set_option */"; echo "\n"; echo "};\n\n"; return ob_get_clean(); } /** * Generate covenience macros for resource access * * @access public * @return string C code snippet */ function hCode() { return "/* ".$this->name." stream goes here */\n"; } /** * Generate documentation for this resource * * @access public * @param string id basename for extension * @return string DocBook XML code snippet */ function docEntry($base) { return " "; } } ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/Element/Test.php?r=1.1&p=1 Index: pear/CodeGen_PECL/Element/Test.php +++ pear/CodeGen_PECL/Element/Test.php <?php /** * Class for testfile generation as needed for 'make test' * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Test.php,v 1.1 2005/07/18 08:12:36 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */ /** * includes */ require_once "CodeGen/PECL/Element.php"; /** * Class for testfile generation as needed for 'make test' * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Element_Test extends CodeGen_PECL_Element { /** * Constructor * * @access public * @param string testfile basename */ function __construct() { } /** * testfile basename * * @access private * @type string */ var $name = ""; /** * Setter for testcase name * * @access public * @return string value of */ function setName($name) { if (! $this->isName($name)) { return PEAR::raise("'$name' is not a valid test case basename"); } $this->name = $name; if (empty($this->title)) { $this->title = $name; } } /** * Getter for testcase name * * @access public * @return string value of */ function getName() { return $this->name; } /** * Testcase description * * @access private * @type string */ var $title = ""; /** * Getter for testcase title * * @access public * @return string value of */ function getTitle() { return $this->title; } /** * Setter for testcase title * * @access public * @param string new value for */ function setTitle($title) { $this->title = $title; } /** * Test code to decide whether to skip a test * * @access private * @type string */ var $skipif = ""; /** * Getter for skipif test code * * @access public * @return string value of */ function getSkipif() { return $this->skipif; } /** * Setter for skipif testcode * * @access public * @param string new value for */ function setSkipIf($code) { $this->skipif = $code; } /** * GET data * * @access private * @type string */ var $get = false; /** * Getter for GET data * * @access public * @return string value of */ function getGet() { return $this->get; } /** * Setter for GET data * * @access public * @param string new value for */ function setGet($data) { $this->get = $data; } /** * raw POST data * * @access private * @type string */ var $post = false; /** * Getter for raw POST data * * @access public * @return string value of */ function getPost() { return $this->post; } /** * Setter for raw POST data * * @access public * @param string new value for */ function setPost($data) { $this->post = $data; } /** * actual test code * * @access private * @type string */ /** * Getter for test code * * @access public * @return string value of */ function getCode() { return $this->code; } /** * Setter for test code * * @access public * @param string new value for */ function setCode($code) { $this->code = $code; } /** * expected output for test code * * @access private * @type string */ /** * Getter for expected output * * @access public * @return string value of */ function getOutput() { return $this->output; } /** * Setter for expected output * * @access public * @param string new value for */ function setOutput($data) { $this->output = $data; } /** * all required properties set? * * @access public * @return bool */ function complete() { if (empty($this->code)) return PEAR::raiseError("no code specified for test case"); if (empty($this->output)) return PEAR::raiseError("no output specified for test case"); return true; } /** * generate testcase file * * @access public * @param object the complete extension context */ function writeTest($extension) { ob_start(); echo "--TEST--\n{$this->name}\n"; if (!empty($this->skipif)) { echo "--SKIPIF--\n{$this->skipif}\n"; } if (!empty($this->post)) { echo "--POST--\n{$this->post}\n"; } if (!empty($this->get)) { echo "--GET--\n{$this->get}\n"; } echo "--FILE--\n{$this->code}"; echo "--EXPECT--\n{$this->output}"; $fp = fopen("{$extension->name}/tests/{$this->name}.phpt", "w"); fputs($fp, ob_get_contents()); ob_end_clean(); fclose($fp); } } ?> http://cvs.php.net/co.php/pear/CodeGen_PECL/examples/logo.xml?r=1.1&p=1 Index: pear/CodeGen_PECL/examples/logo.xml +++ pear/CodeGen_PECL/examples/logo.xml <?xml version="1.0" ?> <extension name="example"> <logo> <![CDATA[ R0lGODdhFQASAOMAAMDEwJCQkLCwsGhoaFhcWLjAuDA0MPj8+FBUUPj4+AAA AAAAAAAAAAAAAAAAAAAAACwAAAAAFQASAAAEehDISWsNQIhBuv+DphWhABhH qq5GpgHluc5HK24vmiKGwfeIgdAU0wkSyCQSkAhgQhgdQUlNCAKkq0BaVWqh 29S0i8QRtFyyNXQOhA9jshktVq8F7Xe8O3en5WxXTgEcdn2DAwF2hHiCGoQc HASSQgRukwiZmpucmwYRADs= ]]> </logo> </extension>
« previous php.pear.cvs (#33099) next »