diff options
author | Hartmut Holzgraefe <hholzgra@php.net> | 2003-02-19 10:07:22 +0000 |
---|---|---|
committer | Hartmut Holzgraefe <hholzgra@php.net> | 2003-02-19 10:07:22 +0000 |
commit | 1dc3726ff2881f06716340fb74c35dfba094c0af (patch) | |
tree | a64885bf135dd1ec40acc82864105cd94cbe7fb8 /scripts | |
parent | 71e6110bc87babf952f93c0d0122c936925dbd22 (diff) | |
download | php-git-1dc3726ff2881f06716340fb74c35dfba094c0af.tar.gz |
next generation ext_skel script - initial checkin
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/ext_skel_ng/README | 36 | ||||
-rw-r--r-- | scripts/ext_skel_ng/ext_skel_ng.php | 13 | ||||
-rw-r--r-- | scripts/ext_skel_ng/extension.dtd | 80 | ||||
-rw-r--r-- | scripts/ext_skel_ng/extension.xml | 82 | ||||
-rw-r--r-- | scripts/ext_skel_ng/extension_parser.php | 789 | ||||
-rw-r--r-- | scripts/ext_skel_ng/php_constant.php | 38 | ||||
-rw-r--r-- | scripts/ext_skel_ng/php_element.php | 74 | ||||
-rw-r--r-- | scripts/ext_skel_ng/php_function.php | 210 | ||||
-rw-r--r-- | scripts/ext_skel_ng/xml_stream_callback_parser.php | 35 | ||||
-rw-r--r-- | scripts/ext_skel_ng/xml_stream_parser.php | 42 |
10 files changed, 1399 insertions, 0 deletions
diff --git a/scripts/ext_skel_ng/README b/scripts/ext_skel_ng/README new file mode 100644 index 0000000000..10d5cfd355 --- /dev/null +++ b/scripts/ext_skel_ng/README @@ -0,0 +1,36 @@ +sorry, no real documentation yet ... +just a short look at what is going on + +ext_skel_ng.php gets an extension description +from an "extension.xml" file and generates working +code and documentation stubs from that + +call "php ext_skel_ng.php" to see it at work, +it will create a dummy extension including + +- module globals and ini paramter setup +- function registration and stubbs +- documentation framework +- config.m4 (only minimal for now) +- ... + +almost every aspect of an extension may now be +configured using one xml description file instead +of the old mixture of command line parameters +and a proto file + +it is even possible to embed function code into +the xml description right away, so it should be +possible to create complete working extensions +from just the xml description without further +editing in a not to distant future + +for now almost all the 'helpfull comments' have +been removed from the generated code. some of +them (like 'uncomment this if you have ini params) +just don't make sense anymore, others will come +back (configurable) at a later state + +... have fun! + +Hartmut Holzgraefe <hholzgra@php.net> diff --git a/scripts/ext_skel_ng/ext_skel_ng.php b/scripts/ext_skel_ng/ext_skel_ng.php new file mode 100644 index 0000000000..8cedd63d4d --- /dev/null +++ b/scripts/ext_skel_ng/ext_skel_ng.php @@ -0,0 +1,13 @@ +<?php + require_once "extension_parser.php"; + + $ext = &new extension_parser(fopen("extension.xml", "r")); + + system("rm -rf {$ext->name}"); + mkdir($ext->name); + + $ext->write_config_m4(); + $ext->write_header_file(); + $ext->write_code_file(); + $ext->generate_documentation(); +?>
\ No newline at end of file diff --git a/scripts/ext_skel_ng/extension.dtd b/scripts/ext_skel_ng/extension.dtd new file mode 100644 index 0000000000..533dac8a7b --- /dev/null +++ b/scripts/ext_skel_ng/extension.dtd @@ -0,0 +1,80 @@ +<!-- + --> + +<!ELEMENT extension (name|summary|description|license|maintainers|release|changelog|functions|constants|globals|deps)*> +<!ATTLIST extension type (source|binary|empty) "empty" + version CDATA #REQUIRED> + +<!ELEMENT name (#PCDATA)> + +<!ELEMENT summary (#PCDATA)> + +<!ELEMENT description (#PCDATA)> + +<!ELEMENT maintainers (maintainer)+> + +<!ELEMENT maintainer (user|role|name|email)*> + +<!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*)> +<!ATTLIST function + name CDATA #REQUIRED +> +<!ELEMENT proto (#PCDATA)> + +<!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 CDATA #REQUIRED + value CDATA #REQUIRED + access (system|perdir|user|all) "all" + onupdate CDATA #IMPLIED +> +<!ELEMENT global (#PCDATA)> +<!ATTLIST global + name CDATA #REQUIRED + type CDATA #REQUIRED +> + +<!ELEMENT deps (with|lib|header|file|program)*> +<!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 +>
\ No newline at end of file diff --git a/scripts/ext_skel_ng/extension.xml b/scripts/ext_skel_ng/extension.xml new file mode 100644 index 0000000000..f9b485d452 --- /dev/null +++ b/scripts/ext_skel_ng/extension.xml @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<!DOCTYPE extension SYSTEM "extension.dtd"> +<extension version="0.1"> + <name>dummy</name> + <summary>experimental dummy extension</summary> + <description> + this is used for testing of the extension generater only + </description> + + <maintainers> + <maintainer> + <user>hholzgra</user> + <name>Hartmut Holzgraefe</name> + <email>hholzgra@php.net</email> + <role>lead</role> + </maintainer> + <maintainer> + <user>dummy</user> + <name>Crashtest Dummy</name> + <email>dummy@example.com</email> + <role>dummy</role> + </maintainer> + </maintainers> + + <release> + <version>0.1</version> + <date>2002-02-16</date> + <state>alpha</state> + <license>other</license> + <notes> + - first experimental draft + </notes> + </release> + + <changelog> + </changelog> + + + <deps> + <!-- these are not yet used in any way :( --> + <with defaults='/usr:/usr/local' testfile='include/dummy.h'></with> + <lib name='dummy' function='dummy' searchpath='/usr/lib:/lib'></lib> + </deps> + + <constants> + <constant name="DUMMY_OK" type="int" value="1">dummy ok status</constant> + <constant name="DUMMY_ERR" type="int" value="0">dummy fault status</constant> + </constants> + + <globals> + <global name="foobar" type="int"></global> + <phpini name="foo_int" type="int" value="42" access="system"></phpini> + <phpini name="foo_bool" type="int" value="on" access="all" onupdate="OnUpdateBool"></phpini> + <phpini name="foo_string" type="string" value="foobar" access="all" ></phpini> + </globals> + + <functions> + + <function name='dummy_int'> + <summary>dummy integer conversion</summary> + <proto>int dummy_int(int bar)</proto> + <description> +some funcy longer description + +foo +bar + </description> + </function> + + <function name='dummy_string'> + <summary>dummy string conversion</summary> + <proto>string dummy_string(string bar) foobar</proto> + <code> +<![CDATA[ + RETURN_STRINGL(bar, bar_len, 1); +]]> + </code> + </function> + + </functions> + +</extension>
\ No newline at end of file diff --git a/scripts/ext_skel_ng/extension_parser.php b/scripts/ext_skel_ng/extension_parser.php new file mode 100644 index 0000000000..81400f8fba --- /dev/null +++ b/scripts/ext_skel_ng/extension_parser.php @@ -0,0 +1,789 @@ +<?php + // {{{ includes + + require_once "php_element.php"; + require_once "php_constant.php"; + require_once "php_function.php"; + + require_once "xml_stream_parser.php"; + require_once "xml_stream_callback_parser.php"; + + // }}} + + class extension_parser extends xml_stream_callback_parser { + + // {{{ constructor + + function extension_parser($stream) { + $this->template_dir = dirname(realpath(__FILE__))."/templates"; + + $this->name = "foobar"; + + $this->license = "php"; + + $this->constants = array(); + $this->functions = array(); + $this->globals = array(); + $this->phpini = array(); + $this->users = array(); + $this->dependson = array(); + + parent::xml_stream_callback_parser($stream); + } + + // }}} + + // {{{ parsing + + // {{{ general infos + + function handle_extension_name($attr) { + $this->name = trim($this->cdata); + } + + function handle_extension_summary($attr) { + $this->summary = trim($this->cdata); + } + + function handle_extension_description($attr) { + $this->description = $this->cdata; + } + + function handle_release_version($attr) { + $this->version = trim($this->cdata); + } + + function handle_maintainers_maintainer_user($attr) { + $this->user["user"] = trim($this->cdata); + } + + function handle_maintainers_maintainer_name($attr) { + $this->user["name"] = trim($this->cdata); + } + + function handle_maintainers_maintainer_email($attr) { + $this->user["email"] = trim($this->cdata); + } + + function handle_maintainers_maintainer_role($attr) { + $this->user["role"] = trim($this->cdata); + } + + function handle_maintainers_maintainer($attr) { + $this->users[$this->user["name"]] = $this->user; + unset($this->user); + } + + // }}} + + // {{{ constants + + function handle_constants_constant($attr) { + $name = $attr["name"]; + $value= $attr["value"]; + $type = isset($attr["type"]) ? $attr["type"] : "string"; + + switch($type) { + case "int": + case "integer": + if (!is_numeric($value)) $this->error("invalid value for integer constant: '$value'"); + if ((int)$value != $value) $this->error("invalid value for integer constant: '$value'"); + $this->constants[] = &new php_constant($name, (int)$value, "integer", trim($this->cdata)); + break; + + case "float": + case "double": + case "real": + if (!is_numeric($value)) $this->error("invalid value for integer constant: '$value'"); + $this->constants[] = &new php_constant($name, $value, "float", trim($this->cdata)); + break; + + case "string": + default: + $this->constants[] = &new php_constant($name, $value, "string", trim($this->cdata)); + break; + } + } + + // }}} + + // {{{ functions + + function handle_functions_function_summary($attr) { + $this->func_summary = trim($this->cdata); + } + + function handle_functions_function_proto($attr) { + $this->func_proto = trim($this->cdata); + } + + function handle_functions_function_description($attr) { + $this->func_desc = trim($this->cdata); + } + + function handle_functions_function_code($attr) { + $this->func_code = $this->cdata; + } + + function handle_functions_function($attr) { + $this->functions[$attr['name']] = new php_function($attr['name'], $this->func_summary, $this->func_proto, @$this->func_desc, @$this->func_code); + unset($this->func_summary); + unset($this->func_proto); + unset($this->func_desc); + unset($this->func_code); + } + + // }}} + + // {{{ globals and php.ini + + function handle_globals_global($attr) { + if($attr["type"] == "string") $attr["type"] = "char*"; + $this->globals[$attr["name"]] = $attr; + } + + function handle_globals_phpini($attr) { + $ini = array("name" => $attr["name"], + "type" => $attr["type"], + "value"=> $attr["value"] + ); + switch($attr["access"]) { + case "system": + $ini["access"] = "PHP_INI_SYSTEM"; + break; + case "perdir": + $ini["access"] = "PHP_INI_PERDIR"; + break; + case "user": + $ini["access"] = "PHP_INI_USER"; + break; + case "all": + default: + $ini["access"] = "PHP_INI_ALL"; + break; + } + if(isset($attr["onupdate"])) { + $ini["onupdate"] = $attr["onupdate"]; + } else { + switch($attr["type"]) { + case "int": + case "long": + $ini["onupdate"] = "OnUpdateInt"; + break; + case "float": + case "double": + $ini["onupdate"] = "OnUpdateFloat"; + break; + case "string": + $ini["type"] = "char*"; + // fallthru + case "char*": + $ini["onupdate"] = "OnUpdateString"; + break; + } + } + $this->phpini[$attr["name"]] = $ini; + $this->handle_globals_global($attr); + } + + // }}} + + // }}} + + // {{{ output generation + + // {{{ docbook documentation + + function generate_documentation() { + system("rm -rf {$this->name}/manual"); + mkdir("{$this->name}/manual"); + + $docdir = "{$this->name}/manual/".$this->name; + mkdir($docdir); + + $fp = fopen("$docdir/reference.xml", "w"); + fputs($fp, +"<?xml version='1.0' encoding='iso-8859-1'?> +<!-- \$Revision$ --> + <reference id='ref.{$this->name}'> + <title>{$this->summary}</title> + <titleabbrev>{$this->name}</titleabbrev> + + <partintro> + <section id='{$this->name}.intro'> + &reftitle.intro; + <para> +{$this->description} + </para> + </section> + + <section id='{$this->name}.requirements'> + &reftitle.required; + <para> + </para> + </section> + + &reference.{$this->name}.configure; + + <section id='{$this->name}.configuration'> + &reftitle.runtime; + &no.config; + </section> + + <section id='{$this->name}.resources'> + &reftitle.resources; + &no.resource; + </section> + + <section id='{$this->name}.constants'> + &reftitle.constants; + &no.constants; + </section> + + </partintro> + +&reference.{$this->name}.functions; + + </reference> +"); + fputs($fp, php_element::docbook_editor_footer()); + + 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->docbook_xml()); + fclose($funcfile); + } + } + + // }}} + + // {{{ extension entry + + function generate_extension_entry() { + return ' +/* {{{ '.$this->name.'_module_entry + */ +zend_module_entry '.$this->name.'_module_entry = { + STANDARD_MODULE_HEADER, + "'.$this->name.'", + '.$this->name.'_functions, + PHP_MINIT('.$this->name.'), /* Replace with NULL if there is nothing to do at php startup */ + PHP_MSHUTDOWN('.$this->name.'), /* Replace with NULL if there is nothing to do at php shutdown */ + PHP_RINIT('.$this->name.'), /* Replace with NULL if there is nothing to do at request start */ + PHP_RSHUTDOWN('.$this->name.'), /* Replace with NULL if there is nothing to do at request end */ + PHP_MINFO('.$this->name.'), + "'.$this->version.'", + STANDARD_MODULE_PROPERTIES +}; +/* }}} */ + +#ifdef COMPILE_DL_'.strtoupper($this->name).' +ZEND_GET_MODULE('.$this->name.') +#endif +'; + } + + // }}} + + // {{{ globals and ini + + function generate_globals_c() { + if (empty($this->globals)) return ""; + + $code = "ZEND_DECLARE_MODULE_GLOBALS({$this->name})\n\n"; + + if (!empty($this->phpini)) { + $code .= "PHP_INI_BEGIN()\n"; + foreach ($this->phpini as $name => $ini) { + $code .= " STD_PHP_INI_ENTRY(\"{$this->name}.$name\", \"$ini[value]\", $ini[access], $ini[onupdate], $name, zend_{$this->name}_globals, {$this->name}_globals)\n"; + } + $code .= "PHP_INI_END()\n\n"; + $code .= "static void php_{$this->name}_init_globals(zend_{$this->name}_globals *{$this->name}_globals)\n"; + $code .= "{\n"; + foreach ($this->globals as $name => $ini) { + $code .= " {$this->name}_globals->$name = "; + if (strstr($ini["type"],"*")) { + $code .= "NULL;\n"; + } else { + $code .= "0;\n"; + } + } + $code .= "}\n\n"; + return $code; + } + } + + function generate_globals_h() { + if (empty($this->globals)) return ""; + + $code = "ZEND_BEGIN_MODULE_GLOBALS({$this->name})\n"; + foreach($this->globals as $name => $global) { + $code .= " $global[type] $name;\n"; + } + $code.= "ZEND_END_MODULE_GLOBALS({$this->name})\n"; + + $upname = strtoupper($this->name); + + $code.= " + +#ifdef ZTS +#define {$upname}_G(v) TSRMG({$this->name}_globals_id, zend_{$this->name}_globals *, v) +#else +#define {$upname}_G(v) ({$this->name}_globals.v) +#endif + +"; + + return $code; + } + + // }}} + + // {{{ license and authoers + + function get_license() { + $code = "/*\n"; + switch($this->license) { + case "php": + $code.= +' +----------------------------------------------------------------------+ + | PHP Version 4 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2002 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.02 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.php.net/license/2_02.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | +'; + break; + + default: + $code.= +" +----------------------------------------------------------------------+ + | unkown license: '{$this->license}' | + +----------------------------------------------------------------------+ +"; + break; + } + + $code.= " +----------------------------------------------------------------------+\n"; + $prefix = "Authors: "; + foreach($this->users as $name => $user) { + $code .= sprintf(" | $prefix %-58s |\n", "$user[name] <$user[email]>"); + $prefix = str_repeat(" ",strlen($prefix)); + } + $code.= " +----------------------------------------------------------------------+\n"; + $code.= "*/\n\n"; + + $code.= "/* $ Id: $ */ \n\n"; + + return $code; + } + + // }}} + + // {{{ editor config footer + + function editor_config_c() { + 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 + */ +'; + } + + // }}} + + // {{{ header file + + function write_header_file() { + $fp = fopen("{$this->name}/php_{$this->name}.h", "w"); + + $upname = strtoupper($this->name); + + fputs($fp, $this->get_license()); + fputs($fp, "#ifndef PHP_{$upname}_H\n"); + fputs($fp, "#define PHP_{$upname}_H\n\n"); + + fputs($fp, "#ifndef PHP_HAVE_{$upname}\n\n"); + + fputs($fp, " +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 + +"); + + fputs($fp, $this->generate_globals_h()); + + fputs($fp, "\n"); + + foreach($this->functions as $name => $function) { + fputs($fp, "PHP_FUNCTION($name);\n"); + } + + fputs($fp, "\n"); + + fputs($fp, "#endif /* PHP_HAVE_{$upname} */\n\n"); + fputs($fp, "#endif /* PHP_{$upname}_H */\n\n"); + + fputs($fp, $this->editor_config_c()); + + fclose($fp); + } + + // }}} + + // {{{ internal functions + + function internal_functions_c() { + $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, NULL)\n"; + } + + if(count($this->phpini)) { + $code .= " REGISTER_INI_ENTRIES();\n"; + } + + $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"; + } + + $code .="\n /* add your stuff here */\n"; + + $code .= " + return SUCCESS; +} +/* }}} */ + +"; + + $code .= " +/* {{{ PHP_RINIT_FUNCTION */ +PHP_RINIT_FUNCTION({$this->name}) +{ + /* add your stuff here */ + + return SUCCESS; +} +/* }}} */ + +"; + + $code .= " +/* {{{ PHP_RSHUTDOWN_FUNCTION */ +PHP_RSHUTDOWN_FUNCTION({$this->name}) +{ + /* add your stuff here */ + + return SUCCESS; +} +/* }}} */ + +"; + + $code .= " +/* {{{ PHP_MINFO_FUNCTION */ +PHP_MINFO_FUNCTION({$this->name}) +{ + php_info_print_table_start(); + php_info_print_table_header(2, \"{$this->name} support\", \"enabled\"); + php_info_print_table_end(); + + /* add your stuff here */ +"; + +if(count($this->phpini)) { + $code .= "\n DISPLAY_INI_ENTRIES();"; +} +$code .= " +} +/* }}} */ + +"; + + return $code; + } + + // }}} + + + // {{{ public functions + + function public_functions_c() { + $code = ""; + + foreach ($this->functions as $name => $func) { + + $code .= "\n/* {{{ func {$func->returns} {$func->name}("; + if (isset($func->params)) { + foreach ($func->params as $key => $param) { + if (!empty($param['optional'])) $code.=" ["; + if ($key) $code.=", "; + $code .= $param['type']." "; + $code .= isset($param['name']) ? $param['name'] : "par_$key"; + } + } + for ($n=$func->optional; $n>0; $n--) { + $code .= "]"; + } + $code .= ")\n "; + if(!empty($func->summary)) $code .= $func->summary; + $code .= " */\n"; + + $code .= "PHP_FUNCTION({$func->name})\n"; + $code .= "{\n"; + $code .= "\tint argc = ZEND_NUM_ARGS();\n\n"; + + if (isset($func->params)) { + $arg_string=""; + $arg_pointers=array(); + $optional=false; + $res_fetch=""; + + foreach ($func->params as $key => $param) { + $name = isset($param['name']) ? $param['name'] : "par_$key"; + $arg_pointers[]="&$name"; + if(isset($param['optional'])&&!$optional) { + $optional=true; + $arg_string.="|"; + } + + switch($param['type']) { + case "void": + break; + + case "bool": + $arg_string.="b"; + $code .= "\tzend_bool $name = 0;\n"; + break; + + case "int": + $arg_string.="l"; + $code .= "\tlong $name = 0;\n"; + break; + + case "float": + $arg_string.="d"; + $code .= "\tdouble $name = 0.0;\n"; + break; + + case "string": + $arg_string.="s"; + $code .= "\tchar * $name = NULL;\n"; + $code .= "\tint {$name}_len = 0;\n"; + $arg_pointers[]="&{$name}_len"; + break; + + case "array": + $arg_string.="a"; + $code .= "\tzval * $name = NULL;\n"; + break; + + case "object": + $arg_string.="o"; + $code .= "\tzval * $name = NULL;\n"; + break; + + case "resource": + $arg_string.="r"; + $code .= "\tzval * $name = NULL;\n"; + $code .= "\tint * {$name}_id = -1;\n"; + $arg_pointers[]="&{$name}_id"; + $res_fetch.="\tif ($name) {\n" + ."\t\tZEND_FETCH_RESOURCE(???, ???, $name, {$name}_id, \"???\", ???_rsrc_id);\n" + ."\t}\n"; + break; + + case "mixed": + $arg_string.="z"; + $code .= "\tzval * $name = NULL;\n"; + break; + } + } + + $code .= "\n\tif (zend_parse_parameters(argc TSRMLS_CC, \"$arg_string\", ".join(", ",$arg_pointers).") == FAILURE) return;\n"; + if($res_fetch) $code.="\n$res_fetch\n"; + } else { + $code .= "\tif(argc>0) { WRONG_PARAM_COUNT; }\n"; + } + + $code .= "\n"; + + if (!empty($func->code)) { + $code .= $func->code."\n"; + } else { + $code .= "\tphp_error(E_WARNING, \"{$func->name}: not yet implemented\");\n\n"; + + switch($func->returns) { + case "void": + break; + + case "bool": + $code .= "\tRETURN_FALSE;\n"; + break; + + case "int": + $code .= "\tRETURN_LONG(0);\n"; + break; + + case "float": + $code .= "\tRETURN_DOUBLE(0.0);\n"; + break; + + case "string": + $code .= "\tRETURN_STRINGL(\"\", 0, 1);\n"; + break; + + case "array": + $code .= "\tarray_init(return_value);\n"; + break; + + case "object": + $code .= "\tobject_init(return_value)\n"; + break; + + case "resource": + $code .= "\t/* RETURN_RESOURCE(...); /*\n"; + break; + + case "mixed": + $code .= "\t/* RETURN_...(...); /*\n"; + break; + } + } + + + $code .= "}\n/* }}} */\n\n"; + } + + + return $code; + } + + // }}} + + + // {{{ code file + + function write_code_file() { + $fp = fopen("{$this->name}/{$this->name}.c", "w"); + + $upname = strtoupper($this->name); + + fputs($fp, $this->get_license()); + + fputs($fp, ' +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <php.h> +#include <php_ini.h> +#include <ext/standard/info.h> + +'); + fputs($fp, "#include \"php_{$this->name}.h\"\n\n"); + + if (!empty($this->globals)) { + fputs($fp, "ZEND_DECLARE_MODULE_GLOBALS({$this->name})\n\n"); + } + + fputs($fp, "/* {{{ {$this->name}_functions[] */\n"); + fputs($fp, "function_entry {$this->name}_functions[] = {\n"); + foreach($this->functions as $name => $function) { + fputs($fp, sprintf(" PHP_FE(%-20s, NULL)\n",$name)); + } + fputs($fp, "};\n/* }}} */\n\n"); + + fputs($fp, $this->generate_extension_entry()); + + fputs($fp, "\n/* {{{ globals and ini entries */\n"); + fputs($fp, $this->generate_globals_c()); + fputs($fp, "/* }}} */\n\n"); + + fputs($fp, $this->internal_functions_c()); + + fputs($fp, $this->public_functions_c()); + + fputs($fp, $this->editor_config_c()); + } + + // }}} + + + function write_config_m4() { + + $upname = $this->name; + + $fp = fopen("{$this->name}/config.m4", "w"); + fputs($fp, +"dnl +dnl \$ Id: \$ +dnl + +PHP_ARG_ENABLE({$this->name} , whether to enable {$this->name} functions, +[ --disable-{$this->name} Disable {$this->name} functions], yes) + +if test \"\$PHP_$upname\" != \"no\"; then + AC_DEFINE(HAVE_$upname, 1, [ ]) + PHP_NEW_EXTENSION({$this->name}, {$this->name}.c, \$ext_shared) +fi +"); + fclose($fp); + } + + // }}} + + } + +?>
\ No newline at end of file diff --git a/scripts/ext_skel_ng/php_constant.php b/scripts/ext_skel_ng/php_constant.php new file mode 100644 index 0000000000..fd1ac36352 --- /dev/null +++ b/scripts/ext_skel_ng/php_constant.php @@ -0,0 +1,38 @@ +<?php + + class php_constant extends php_element { + function php_constant($name, $value, $type="string", $desc="") { + $this->name = $name; + $this->value= $value; + $this->type = $type; + $this->desc = $desc; + } + + function c_code() { + switch($this->type) { + case "integer": + return "REGISTER_LONG_CONSTANT(\"{$this->name}\", {$this->value}, 0);\n"; + + case "float": + return "REGISTER_DOUBLE_CONSTANT(\"{$this->name}\", {$this->value}, 0);\n"; + + case "string": + return "REGISTER_STRING_CONSTANT(\"{$this->name}\", \"$value\", ".strlen($this->value).", 0);\n"; + } + } + + function docbook_xml() { + return trim(" +<row> + <entry> + <constant id='constant".strtolower(str_replace("_","-",$this->name))."'>$name</constant> + (<link linkend='language.types.integer'>integer</link>) + </entry> + <entry>{$this->value}</entry> + <entry>{$this->desc}</entry> +</row> +")."\n"; + } + } + +?>
\ No newline at end of file diff --git a/scripts/ext_skel_ng/php_element.php b/scripts/ext_skel_ng/php_element.php new file mode 100644 index 0000000000..83de9dc110 --- /dev/null +++ b/scripts/ext_skel_ng/php_element.php @@ -0,0 +1,74 @@ +<?php + +class php_element { + function is_type($name) { + $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" => "mixes", + ); + + if(isset($types[$name])) { + return $types[$name]; + } else { + return false; + } + } + + function is_name($name) { + if(ereg("[a-zA-Z0-9_]",$name)) { + // TODO reserved words + return true; + } + return false; + } + + + function c_code() { + return ""; + } + + function h_code() { + return ""; + } + + function docbook_xml() { + return ""; + } + + function docbook_editor_footer($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 +--> +'; + } +} + +?>
\ No newline at end of file diff --git a/scripts/ext_skel_ng/php_function.php b/scripts/ext_skel_ng/php_function.php new file mode 100644 index 0000000000..c9abe73035 --- /dev/null +++ b/scripts/ext_skel_ng/php_function.php @@ -0,0 +1,210 @@ +<?php + + class php_function extends php_element { + // all known php types + function php_function($name, $summary, $proto, $desc="", $code="") { + $this->name = $name; + $this->summary = $summary; + $this->parse_proto($proto); + $this->desc = empty($desc) ? "&warn.undocumented.func;" : $desc; + $this->code = $code; + } + + function parse_proto($proto) { + // 'tokenize' it + $len=strlen($proto); + $name=""; + $tokens=array(); + for($n=0;$n<$len;$n++) { + $char = $proto{$n}; + if(ereg("[a-zA-Z0-9_]",$char)) { + $name.=$char; + } else { + if($name) $tokens[]=$name; + $name=""; + if(trim($char)) $tokens[]=$char; + } + } + if($name) $tokens[]=$name; + + $n=0; + $opts=0; + $params=array(); + $return_type = ($this->is_type($tokens[$n])) ? $tokens[$n++] : "void"; + if(! $this->is_name($tokens[$n])) die("$tokens[$n] is not a valid function name"); + $function_name = $tokens[$n++]; + if($tokens[$n]!='(') die("'(' expected instead of '$tokens[$n]'"); + if($tokens[++$n]!=')') { + for($param=0;$tokens[$n];$n++,$param++) { + if($tokens[$n]=='[') { + $params[$param]['optional']=true; + $opts++; + $n++; + if($param>0) { + if ($tokens[$n]!=',') die("',' expected after '[' instead of $token[$n]"); + $n++; + } + } + if(!$this->is_type($tokens[$n])) die("type name expected instead of $tokens[$n]"); + $params[$param]['type']=$tokens[$n]; + $n++; + if($this->is_name($tokens[$n])) { + $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) die ("'[' / ']' count mismatch"); + if($tokens[$n] != ')') die ("')' expected instead of $tokens[$n]"); + + $this->name = $function_name; + $this->returns = $return_type; + $this->params = $params; + $this->optional = $numopts; + } + + function c_code() { + $code .= "\n/* {{{ proto {$this->returns} {$this->name}("; + if(isset($this->params)) { + foreach($this->params as $param) { + if(!empty($param['optional'])) + $code.=" ["; + if($key) + $code.=", "; + $code .= $param['type']." "; + $code .= $param['name']; + } + } + for($n=$this->optional; $n>0; $n--) { + $code .= "]"; + } + $code .= ")\n "; + if(!empty($this->summary)) { + $code .= $this->summary; + } + $code .= " */\n"; + $code .= "PHP_FUNCTION({$this->name})\n"; + $code .= "{\n"; + $code .= "\tint argc = ZEND_NUM_ARGS();\n\n"; + if(isset($this->params)) { + $arg_string=""; + $arg_pointers=array(); + $optional=false; + $res_fetch=""; + foreach($this->params as $param) { + $name = $param['name']; + $arg_pointers[]="&$name"; + if(isset($param['optional'])&&!$optional) { + $optional=true; + $arg_string.="|"; + } + switch($param['type']) { + //case "void": + case "bool": + $arg_string.="b"; + $code .= "\tzend_bool $name = 0;\n"; + break; + case "int": + $arg_string.="l"; + $code .= "\tlong $name = 0;\n"; + break; + case "float": + $arg_string.="d"; + $code .= "\tdouble $name = 0.0;\n"; + break; + case "string": + $arg_string.="s"; + $code .= "\tchar * $name = NULL;\n"; + $code .= "\tint {$name}_len = 0;\n"; + $arg_pointers[]="&{$name}_len"; + break; + case "array": + $arg_string.="a"; + $code .= "\tzval * $name = NULL;\n"; + break; + case "object": + $arg_string.="o"; + $code .= "\tzval * $name = NULL;\n"; + break; + case "resource": + $arg_string.="r"; + $code .= "\tzval * $name = NULL;\n"; + $code .= "\tint * {$name}_id = -1;\n"; + $arg_pointers[]="&{$name}_id"; + $res_fetch.="\tif ($name) {\n" + ."\t\tZEND_FETCH_RESOURCE(???, ???, $name, {$name}_id, \"???\", ???_rsrc_id);\n" + ."\t}\n"; + break; + case "mixed": + $arg_string.="z"; + $code .= "\tzval * $name = NULL;\n"; + break; + } + } + $code .= "\n\tif (zend_parse_parameters(argc TSRMLS_CC, \"$arg_string\", ".join(", ",$arg_pointers).") == FAILURE) return;\n"; + if($res_fetch) $code.="\n$res_fetch\n"; + } else { + $code .= "\tif(argc>0) { WRONG_PARAM_COUNT; }\n\n"; + } + $code .= "\tphp_error(E_WARNING, \"{$this->name}: not yet implemented\");\n"; + $code .= "}\n/* }}} */\n\n"; + + return $code; + } + + function docbook_xml() { + $xml = +'<?xml version="1.0" encoding="iso-8859-1"?> +<!-- $Revision$ --> + <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)) { + $xml .= " <void/>\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>$param[name]</parameter>"; + $xml .= "</methodparam>\n"; + } + } + +$xml .= +' </methodsynopsis> + <para> +'.$this->desc.' + </para> + </refsect1> + </refentry> +'; + $xml .= $this->docbook_editor_footer(4); + + return $xml; + } + } + +?>
\ No newline at end of file diff --git a/scripts/ext_skel_ng/xml_stream_callback_parser.php b/scripts/ext_skel_ng/xml_stream_callback_parser.php new file mode 100644 index 0000000000..50f1a1c5be --- /dev/null +++ b/scripts/ext_skel_ng/xml_stream_callback_parser.php @@ -0,0 +1,35 @@ +<?php + class xml_stream_callback_parser extends xml_stream_parser { + function xml_stream_callback_parser ($stream) { + $this->cdata = ""; + $this->tags = array(); + $this->attrs = array(); + + parent::xml_stream_parser($stream); + } + + function cdata($parser, $cdata) { + $this->cdata .= $cdata; + } + + function tag_open($parser, $tag, $attributes) { + array_push($this->tags, $tag); + array_push($this->attrs, $attributes); + } + + function tag_close($parser, $tag) { + $attributes = array_pop($this->attrs); + + for ($tags = $this->tags; count($tags); array_shift($tags)) { + $method = "handle_".join("_", $tags); + if(method_exists($this, $method)) { + $this->$method($attributes); + break; + } + } + + $this->cdata = ""; + array_pop($this->tags); + } + } +?>
\ No newline at end of file diff --git a/scripts/ext_skel_ng/xml_stream_parser.php b/scripts/ext_skel_ng/xml_stream_parser.php new file mode 100644 index 0000000000..626c50b154 --- /dev/null +++ b/scripts/ext_skel_ng/xml_stream_parser.php @@ -0,0 +1,42 @@ +<?php +class xml_stream_parser { + var $parser; + + function xml_stream_parser($stream) + { + if(!is_resource($stream)) die("not a stream"); + if(get_resource_type($stream) != "stream") die("not a stream"); + + $this->parser = xml_parser_create(); + + xml_set_object($this->parser, $this); + xml_set_element_handler($this->parser, "tag_open", "tag_close"); + xml_set_character_data_handler($this->parser, "cdata"); + xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, false); + + while(!feof($stream)) { + xml_parse($this->parser, fgets($stream), feof($stream)); + } + xml_parser_free($this->parser); + } + + function tag_open($parser, $tag, $attributes) + { + var_dump($parser, $tag, $attributes); + } + + function cdata($parser, $cdata) + { + var_dump($parser, $cdata); + } + + function tag_close($parser, $tag) + { + var_dump($parser, $tag); + } + + function error($msg) { + die("$msg in line ".xml_get_current_line_number($this->parser)); + } +} // end of class xml +?>
\ No newline at end of file |