Browse Source

next generation ext_skel script - initial checkin

PHP-5
Hartmut Holzgraefe 23 years ago
parent
commit
1dc3726ff2
  1. 36
      scripts/ext_skel_ng/README
  2. 13
      scripts/ext_skel_ng/ext_skel_ng.php
  3. 80
      scripts/ext_skel_ng/extension.dtd
  4. 82
      scripts/ext_skel_ng/extension.xml
  5. 789
      scripts/ext_skel_ng/extension_parser.php
  6. 38
      scripts/ext_skel_ng/php_constant.php
  7. 74
      scripts/ext_skel_ng/php_element.php
  8. 210
      scripts/ext_skel_ng/php_function.php
  9. 35
      scripts/ext_skel_ng/xml_stream_callback_parser.php
  10. 42
      scripts/ext_skel_ng/xml_stream_parser.php

36
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>

13
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();
?>

80
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
>

82
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>

789
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);
}
// }}}
}
?>

38
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";
}
}
?>

74
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
-->
';
}
}
?>

210
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;
}
}
?>

35
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);
}
}
?>

42
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
?>
Loading…
Cancel
Save