summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.EXT_SKEL196
-rwxr-xr-xext/ext_skel284
-rw-r--r--ext/ext_skel_win32.php52
-rw-r--r--ext/skeleton/CREDITS1
-rw-r--r--ext/skeleton/EXPERIMENTAL0
-rwxr-xr-xext/skeleton/create_stubs289
-rw-r--r--ext/skeleton/php_skeleton.h56
-rw-r--r--ext/skeleton/skeleton.c167
-rw-r--r--ext/skeleton/skeleton.dsp113
-rw-r--r--ext/skeleton/skeleton.php19
-rw-r--r--ext/skeleton/tests/001.phpt24
11 files changed, 1199 insertions, 2 deletions
diff --git a/README.EXT_SKEL b/README.EXT_SKEL
index 261f72caf7..599e6997c4 100644
--- a/README.EXT_SKEL
+++ b/README.EXT_SKEL
@@ -1,2 +1,194 @@
-NOTE: ext_skel does no longer exist, it has been replaced
- by the PEAR package PECL_Gen
+(NOTE: you may also want to take a look at the pear package
+ PECL_Gen, a PHP-only alternative for this script that
+ supports way more extension writing tasks and is
+ supposed to replace ext_skel completely in the long run ...)
+
+WHAT IT IS
+
+ It's a tool for automatically creating the basic framework for a PHP module
+ and writing C code handling arguments passed to your functions from a simple
+ configuration file. See an example at the end of this file.
+
+HOW TO USE IT
+
+ Very simple. First, change to the ext/ directory of the PHP 4 sources. If
+ you just need the basic framework and will be writing all the code in your
+ functions yourself, you can now do
+
+ ./ext_skel --extname=module_name
+
+ and everything you need is placed in directory module_name.
+
+ [ Note that GNU awk is likely required for this script to work. Debian
+ systems seem to default to using mawk, so you may need to change the
+ #! line in skeleton/create_stubs and the cat $proto | awk line in
+ ext_skel to use gawk explicitly. ]
+
+ If you don't need to test the existence of any external header files,
+ libraries or functions in them, the module is already almost ready to be
+ compiled in PHP. Just remove 3 comments in your_module_name/config.m4,
+ change back up to PHP sources top directory, and do
+
+ ./buildconf; ./configure --enable-module_name; make
+
+ But if you already have planned the overall scheme of your module, what
+ functions it will contain, their return types and the arguments they take
+ (a very good idea) and don't want to bother yourself with creating function
+ definitions and handling arguments passed yourself, it's time to create a
+ function definitions file, which you will give as an argument to ext_skel
+ with option
+
+ --proto=filename.
+
+FORMAT OF FUNCTION DEFINITIONS FILE
+
+ All the definitions must be on one line. In it's simplest form, it's just
+ the function name, e.g.
+
+ my_function
+
+ but then you'll be left with an almost empty function body without any
+ argument handling.
+
+ Arguments are given in parenthesis after the function name, and are of
+ the form 'argument_type argument_name'. Arguments are separated from each
+ other with a comma and optional space. Argument_type can be one of int,
+ bool, double, float, string, array, object or mixed.
+
+ An optional argument is separated from the previous by an optional space,
+ then '[' and of course comma and optional space, like all the other
+ arguments. You should close a row of optional arguments with same amount of
+ ']'s as there where '['s. Currently, it does not harm if you forget to do it
+ or there is a wrong amount of ']'s, but this may change in the future.
+
+ An additional short description may be added after the parameters.
+ If present it will be filled into the 'proto' header comments in the stubs
+ code and the <refpurpose> tag in the XML documentation.
+
+ An example:
+
+ my_function(int arg1, int arg2 [, int arg3 [, int arg4]]) this is my 1st
+
+ Arguments arg3 and arg4 are optional.
+
+ If possible, the function definition should also contain it's return type
+ in front of the definition. It's not actually used for any C code generating
+ purposes but PHP in-source documentation instead, and as such, very useful.
+ It can be any of int, double, string, bool, array, object, resource, mixed
+ or void.
+
+ The file must contain nothing else but function definitions, no comments or
+ empty lines.
+
+OTHER OPTIONS
+
+ --no-help
+
+ By default, ext_skel creates both comments in the source code and a test
+ function to help first time module writers to get started and testing
+ configuring and compiling their module. This option turns off all such things
+ which may just annoy experienced PHP module coders. Especially useful with
+
+ --stubs=file
+
+ which will leave out also all module specific stuff and write just function
+ stubs with function value declarations and passed argument handling, and
+ function entries and definitions at the end of the file, for copying and
+ pasting into an already existing module.
+
+ --assign-params
+ --string-lens
+
+ By default, function proto 'void foo(string bar)' creates the following:
+ ...
+ zval **bar;
+ ... (zend_get_parameters_ex() called in the middle...)
+ convert_to_string_ex(bar);
+
+ Specifying both of these options changes the generated code to:
+ ...
+ zval **bar_arg;
+ int bar_len;
+ char *bar = NULL;
+ ... (zend_get_parameters_ex() called in the middle...)
+ convert_to_string_ex(bar_arg);
+ bar = Z_STRVAL_PP(bar_arg);
+ bar_len = Z_STRLEN_PP(bar_arg);
+
+ You shouldn't have to ask what happens if you leave --string-lens out. If you
+ have to, it's questionable whether you should be reading this document.
+
+ --with-xml[=file]
+
+ Creates the basics for phpdoc .xml file.
+
+ --full-xml
+
+ Not implemented yet. When or if there will ever be created a framework for
+ self-contained extensions to use phpdoc system for their documentation, this
+ option enables it on the created xml file.
+
+CURRENT LIMITATIONS, BUGS AND OTHER ODDITIES
+
+ Only arguments of types int, bool, double, float, string and array are
+ handled. For other types you must write the code yourself. And for type
+ mixed, it wouldn't even be possible to write anything, because only you
+ know what to expect.
+
+ It can't handle correctly, and probably never will, variable list of
+ of arguments. (void foo(int bar [, ...])
+
+ Don't trust the generated code too much. It tries to be useful in most of
+ the situations you might encounter, but automatic code generation will never
+ beat a programmer who knows the real situation at hand. ext_skel is generally
+ best suited for quickly generating a wrapper for c-library functions you
+ might want to have available in PHP too.
+
+ This program doesn't have a --help option. It has --no-help instead.
+
+EXAMPLE
+
+ The following _one_ line
+
+ bool my_drawtext(resource image, string text, resource font, int x, int y [, int color])
+
+ will create this function definition for you (note that there are a few
+ question marks to be replaced by you, and you must of course add your own
+ value definitions too):
+
+/* {{{ proto bool my_drawtext(resource image, string text, resource font, int x, int y[, int color])
+ */
+PHP_FUNCTION(my_drawtext)
+{
+ zval **image, **text, **font, **x, **y, **color;
+ int argc;
+ int image_id = -1;
+ int font_id = -1;
+
+ argc = ZEND_NUM_ARGS();
+ if (argc < 5 || argc > 6 || zend_get_parameters_ex(argc, &image, &text, &font, &x, &y, &color) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+
+ ZEND_FETCH_RESOURCE(???, ???, image, image_id, "???", ???_rsrc_id);
+ ZEND_FETCH_RESOURCE(???, ???, font, font_id, "???", ???_rsrc_id);
+
+ switch (argc) {
+ case 6:
+ convert_to_long_ex(color);
+ /* Fall-through. */
+ case 5:
+ convert_to_long_ex(y);
+ convert_to_long_ex(x);
+ /* font: fetching resources already handled. */
+ convert_to_string_ex(text);
+ /* image: fetching resources already handled. */
+ break;
+ default:
+ WRONG_PARAM_COUNT;
+ }
+
+ php_error(E_WARNING, "my_drawtext: not yet implemented");
+}
+/* }}} */
+
diff --git a/ext/ext_skel b/ext/ext_skel
new file mode 100755
index 0000000000..3abf341bdf
--- /dev/null
+++ b/ext/ext_skel
@@ -0,0 +1,284 @@
+#!/bin/sh
+
+givup() {
+ echo $*
+ exit 1
+}
+
+usage() {
+echo "$0 --extname=module [--proto=file] [--stubs=file] [--xml[=file]]"
+echo " [--skel=dir] [--full-xml] [--no-help]"
+echo ""
+echo " --extname=module module is the name of your extension"
+echo " --proto=file file contains prototypes of functions to create"
+echo " --stubs=file generate only function stubs in file"
+echo " --xml generate xml documentation to be added to phpdoc-cvs"
+echo " --skel=dir path to the skeleton directory"
+echo " --full-xml generate xml documentation for a self-contained extension"
+echo " (not yet implemented)"
+echo " --no-help don't try to be nice and create comments in the code"
+echo " and helper functions to test if the module compiled"
+exit 1
+}
+
+if test $# = 0; then
+ usage
+fi
+
+while test $# -gt 0; do
+ case "$1" in
+ -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ case $1 in
+ --extname=?*)
+ extname=$optarg
+ EXTNAME=`echo $extname | tr "[:lower:]" "[:upper:]"`
+ ;;
+ --proto=?*)
+ proto=$optarg
+ ;;
+ --stubs=*)
+ stubs=yes
+ stubfile=$optarg
+ ;;
+ --xml)
+ xml="yes"
+ ;;
+ --xml=?*)
+ xml=$optarg
+ ;;
+ --full-xml)
+ full_xml="yes"
+ ;;
+ --no-help)
+ no_help="yes"
+ ;;
+ --skel=?*)
+ skel_dir=$optarg
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ shift
+done
+
+if test -d "$extname" ; then
+ givup "Directory $extname already exists."
+fi
+
+if test -z "$skel_dir"; then
+ skel_dir="skeleton"
+fi
+
+## convert skel_dir to full path
+skel_dir=`cd $skel_dir && pwd`
+
+test -d $skel_dir || givup "directory $skel_dir does not exist or is not directory"
+
+if echo '\c' | grep -s c >/dev/null 2>&1
+then
+ ECHO_N="echo -n"
+ ECHO_C=""
+else
+ ECHO_N="echo"
+ ECHO_C='\c'
+fi
+
+if test -z "$stubs"; then
+ echo "Creating directory $extname"
+ stubfile=$extname"/function_stubs"
+ mkdir $extname || givup "Cannot create directory $extname"
+fi
+
+if test -n "$proto"; then
+ cat $proto | awk -v extname=$extname -v stubs=$stubs -v stubfile=$stubfile -v xml=$xml -v full_xml=$full_xml -v i_know_what_to_do_shut_up_i_dont_need_your_help_mode=$no_help -f $skel_dir/create_stubs
+fi
+
+if test -z "$stubs"; then
+ cd $extname
+ chmod 755 .
+
+$ECHO_N "Creating basic files:$ECHO_C"
+
+$ECHO_N " config.m4$ECHO_C"
+cat >config.m4 <<eof
+dnl \$Id\$
+dnl config.m4 for extension $extname
+
+dnl Comments in this file start with the string 'dnl'.
+dnl Remove where necessary. This file will not work
+dnl without editing.
+
+dnl If your extension references something external, use with:
+
+dnl PHP_ARG_WITH($extname, for $extname support,
+dnl Make sure that the comment is aligned:
+dnl [ --with-$extname Include $extname support])
+
+dnl Otherwise use enable:
+
+dnl PHP_ARG_ENABLE($extname, whether to enable $extname support,
+dnl Make sure that the comment is aligned:
+dnl [ --enable-$extname Enable $extname support])
+
+if test "\$PHP_$EXTNAME" != "no"; then
+ dnl Write more examples of tests here...
+
+ dnl # --with-$extname -> check with-path
+ dnl SEARCH_PATH="/usr/local /usr" # you might want to change this
+ dnl SEARCH_FOR="/include/$extname.h" # you most likely want to change this
+ dnl if test -r \$PHP_$EXTNAME/\$SEARCH_FOR; then # path given as parameter
+ dnl ${EXTNAME}_DIR=\$PHP_$EXTNAME
+ dnl else # search default path list
+ dnl AC_MSG_CHECKING([for $extname files in default path])
+ dnl for i in \$SEARCH_PATH ; do
+ dnl if test -r \$i/\$SEARCH_FOR; then
+ dnl ${EXTNAME}_DIR=\$i
+ dnl AC_MSG_RESULT(found in \$i)
+ dnl fi
+ dnl done
+ dnl fi
+ dnl
+ dnl if test -z "\$${EXTNAME}_DIR"; then
+ dnl AC_MSG_RESULT([not found])
+ dnl AC_MSG_ERROR([Please reinstall the $extname distribution])
+ dnl fi
+
+ dnl # --with-$extname -> add include path
+ dnl PHP_ADD_INCLUDE(\$${EXTNAME}_DIR/include)
+
+ dnl # --with-$extname -> check for lib and symbol presence
+ dnl LIBNAME=$extname # you may want to change this
+ dnl LIBSYMBOL=$extname # you most likely want to change this
+
+ dnl PHP_CHECK_LIBRARY(\$LIBNAME,\$LIBSYMBOL,
+ dnl [
+ dnl PHP_ADD_LIBRARY_WITH_PATH(\$LIBNAME, \$${EXTNAME}_DIR/lib, ${EXTNAME}_SHARED_LIBADD)
+ dnl AC_DEFINE(HAVE_${EXTNAME}LIB,1,[ ])
+ dnl ],[
+ dnl AC_MSG_ERROR([wrong $extname lib version or lib not found])
+ dnl ],[
+ dnl -L\$${EXTNAME}_DIR/lib -lm -ldl
+ dnl ])
+ dnl
+ dnl PHP_SUBST(${EXTNAME}_SHARED_LIBADD)
+
+ PHP_NEW_EXTENSION($extname, $extname.c, \$ext_shared)
+fi
+eof
+
+
+$ECHO_N " .cvsignore$ECHO_C"
+cat >.cvsignore <<eof
+.deps
+*.lo
+*.la
+eof
+
+$ECHO_N " $extname.c$ECHO_C"
+echo "s/extname/$extname/g" > sedscript
+echo "s/EXTNAME/$EXTNAME/g" >> sedscript
+echo '/__function_entries_here__/r function_entries' >> sedscript
+echo '/__function_stubs_here__/r function_stubs' >> sedscript
+echo '/__header_here__/r ../../header' >> sedscript
+echo '/__footer_here__/r ../../footer' >> sedscript
+echo '/__function_entries_here__/D' >> sedscript
+echo '/__function_stubs_here__/D' >> sedscript
+echo '/__header_here__/D' >> sedscript
+echo '/__footer_here__/D' >> sedscript
+if [ ! -z "$no_help" ]; then
+ echo "/confirm_$extname_compiled/D" >> sedscript
+ echo '/Remove the following/,/^\*\//D' >> sedscript
+ echo 's/[[:space:]]\/\*.\+\*\///' >> sedscript
+ echo 's/^\/\*.*\*\/$//' >> sedscript
+ echo '/^[[:space:]]*\/\*/,/^[[:space:]]*\*\//D' >> sedscript
+fi
+
+sed -f sedscript < $skel_dir/skeleton.c > $extname.c
+
+
+$ECHO_N " php_$extname.h$ECHO_C"
+echo "s/extname/$extname/g" > sedscript
+echo "s/EXTNAME/$EXTNAME/g" >> sedscript
+echo '/__function_declarations_here__/r function_declarations' >> sedscript
+echo '/__header_here__/r ../../header' >> sedscript
+echo '/__footer_here__/r ../../footer' >> sedscript
+echo '/__function_declarations_here__/D' >> sedscript
+echo '/__header_here__/D' >> sedscript
+echo '/__footer_here__/D' >> sedscript
+if [ ! -z "$no_help" ]; then
+ echo "/confirm_$extname_compiled/D" >> sedscript
+ echo 's/[[:space:]]\/\*.\+\*\///' >> sedscript
+ echo 's/^\/\*.*\*\/$//' >> sedscript
+ echo '/^[[:space:]]*\/\*/,/^[[:space:]]*\*\//D' >> sedscript
+fi
+sed -f sedscript <$skel_dir/php_skeleton.h > php_$extname.h
+
+$ECHO_N " CREDITS$ECHO_C"
+echo "s/extname/$extname/g" > sedscript
+sed -f sedscript <$skel_dir/CREDITS > CREDITS
+
+$ECHO_N " EXPERIMENTAL$ECHO_C"
+echo "s/extname/$extname/g" > sedscript
+sed -f sedscript <$skel_dir/EXPERIMENTAL > EXPERIMENTAL
+
+$ECHO_N " tests/001.phpt$ECHO_C"
+mkdir tests || givup "Cannot create tests directory"
+chmod 755 tests
+sed -f sedscript <$skel_dir/tests/001.phpt > tests/001.phpt
+
+if test -z "$stubs" && test -z "$no_help"; then
+ $ECHO_N " $extname.php$ECHO_C"
+ sed \
+ -e "s/extname/$extname/g" \
+ <$skel_dir/skeleton.php \
+ > $extname.php
+fi
+
+rm sedscript
+
+if test -n "$proto"; then
+ if test -z "$stubs"; then
+ rm function_entries
+ rm function_declarations
+ rm function_stubs
+ fi
+ if test -f function_warning; then
+ rm function_warning
+ warning="
+NOTE! Because some arguments to functions were resources, the code generated
+cannot yet be compiled without editing. Please consider this to be step 4.5
+in the instructions above.
+"
+ fi
+fi
+
+find . -type f | xargs chmod 644
+find . -type d | xargs chmod 755
+fi
+
+echo " [done]."
+
+if test -z "$no_help" && test -z "$stubs"; then
+ cat <<eof
+
+To use your new extension, you will have to execute the following steps:
+
+1. $ cd ..
+2. $ vi ext/$extname/config.m4
+3. $ ./buildconf
+4. $ ./configure --[with|enable]-$extname
+5. $ make
+6. $ ./php -f ext/$extname/$extname.php
+7. $ vi ext/$extname/$extname.c
+8. $ make
+
+Repeat steps 3-6 until you are satisfied with ext/$extname/config.m4 and
+step 6 confirms that your module is compiled into PHP. Then, start writing
+code and repeat the last two steps as often as necessary.
+$warning
+eof
+fi
diff --git a/ext/ext_skel_win32.php b/ext/ext_skel_win32.php
new file mode 100644
index 0000000000..5036ad21d8
--- /dev/null
+++ b/ext/ext_skel_win32.php
@@ -0,0 +1,52 @@
+<?php
+/* $Id$ */
+
+if (php_sapi_name() != "cli") {
+ echo "Please run this script using the CLI version of PHP\n";
+ exit;
+}
+/*
+ This script can be used on Win32 systems
+
+ 1) Make sure you have CygWin installed
+ 2) Adjust the $cygwin_path to match your installation
+ 3) Change the environment cariable PATHEXT to include .PHP
+ 4) run ext_skel --ext_name=...
+ the first time you run this script you will be asked to
+ associate it with a program. chooses the CLI version of php.
+*/
+
+$cygwin_path = 'c:\cygwin\bin';
+
+$path = getenv("PATH");
+putenv("PATH=$cygwin_path;$path");
+
+array_shift($argv);
+system("sh ext_skel " . implode(" ", $argv));
+
+$extname = "";
+$skel = "skeleton";
+foreach($argv as $arg) {
+ if (strtolower(substr($arg, 0, 9)) == "--extname") {
+ $extname = substr($arg, 10);
+ }
+ if (strtolower(substr($arg, 0, 6)) == "--skel") {
+ $skel = substr($arg, 7);
+ }
+}
+
+$fp = fopen("$skel/skeleton.dsp", "rb");
+if ($fp) {
+ $dsp_file = fread($fp, filesize("$skel/skeleton.dsp"));
+ fclose($fp);
+
+ $dsp_file = str_replace("extname", $extname, $dsp_file);
+ $dsp_file = str_replace("EXTNAME", strtoupper($extname), $dsp_file);
+ $fp = fopen("$extname/$extname.dsp", "wb");
+ if ($fp) {
+ fwrite($fp, $dsp_file);
+ fclose($fp);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/skeleton/CREDITS b/ext/skeleton/CREDITS
new file mode 100644
index 0000000000..58fc71019a
--- /dev/null
+++ b/ext/skeleton/CREDITS
@@ -0,0 +1 @@
+extname \ No newline at end of file
diff --git a/ext/skeleton/EXPERIMENTAL b/ext/skeleton/EXPERIMENTAL
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/ext/skeleton/EXPERIMENTAL
diff --git a/ext/skeleton/create_stubs b/ext/skeleton/create_stubs
new file mode 100755
index 0000000000..61957289d0
--- /dev/null
+++ b/ext/skeleton/create_stubs
@@ -0,0 +1,289 @@
+#!/usr/bin/awk -f
+
+function gobble(s, x)
+{
+ sub(/^ /, "", line)
+ match(line, "^" "(" s ")")
+ x = substr(line, 1, RLENGTH)
+ line = substr(line, RLENGTH+1)
+ return x
+}
+
+function convert(i, j, t)
+{
+ type = argtypes[i,j]
+ name = argnames[i,j]
+ opt = optionals[i,j]
+ tabs = x = ""
+
+ for (i = 0; i < t; i++) { tabs = tabs "\t" }
+
+ if (type == "int" || type == "long") {
+ longs = longs "\tlong " name ";\n"
+ } else if (type == "bool" || type == "boolean") {
+ bools = bools "\tzend_bool " name ";\n"
+ } else if (type == "double" || type == "float") {
+ doubles = doubles "\tdouble " name ";\n"
+ } else if (type == "string") {
+ strings = strings "\tchar *" name " = NULL;\n"
+ ints = ints "\tint " name "_len;\n"
+ } else if (type == "array" || type == "object" || type == "mixed") {
+ zvals = zvals "\tzval *" name " = NULL;\n"
+ } else if (type == "resource" || type == "handle") {
+ zvals = zvals "\tzval *" name " = NULL;\n"
+ resources = resources "\tif (" name ") {\n" \
+ "\t\tZEND_FETCH_RESOURCE(???, ???, " name ", " name "_id, \"???\", ???_rsrc_id);\n\t}\n"
+ ints = ints "\tint " name "_id = -1;\n"
+ }
+}
+
+function comment(s)
+{
+ if (i_know_what_to_do_shut_up_i_dont_need_your_help_mode) {
+ return
+ } else {
+ return s
+ }
+}
+
+BEGIN {
+ name = "[_A-Za-z][_A-Za-z0-9]*"
+ type = "int|long|double|float|string|bool|boolean|array|object|resource|handle|mixed|void"
+ spec = "l|l|d|d|s|b|b|a|o|r|r|z|"
+ num_funcs = 0
+
+# create a map from type name to the spec
+ split(type, type_array, "\|")
+ split(spec, spec_array, "\|")
+ for (i in type_array) {
+ spec_map[type_array[i]] = spec_array[i]
+ }
+
+ if (xml && xml != "yes") {
+ xmldoc = xml
+ } else {
+ xmldoc = extname "/" extname ".xml"
+ }
+
+
+ xmlhead = "<?xml version='1.0' encoding='iso-8859-1'?>\n" \
+ "<!-- $Revision$ -->\n" \
+ " <reference id=\"ref." extname "\">\n" \
+ " <title> functions</title>\n" \
+ " <titleabbrev></titleabbrev>\n\n" \
+ " <partintro>\n" \
+ " &warn.experimental;\n" \
+ " <para>\n" \
+ " </para>\n" \
+ " </partintro>\n\n";
+
+ xmlfoot = " </reference>\n\n" \
+ "<!-- Keep this comment at the end of the file\n" \
+ "Local variables:\n" \
+ "mode: sgml\n" \
+ "sgml-omittag:t\n" \
+ "sgml-shorttag:t\n" \
+ "sgml-minimize-attributes:nil\n" \
+ "sgml-always-quote-attributes:t\n" \
+ "sgml-indent-step:1\n" \
+ "sgml-indent-data:t\n" \
+ "indent-tabs-mode:nil\n" \
+ "sgml-parent-document:nil\n" \
+ "sgml-default-dtd-file:\"../../manual.ced\"\n" \
+ "sgml-exposed-tags:nil\n" \
+ "sgml-local-catalogs:nil\n" \
+ "sgml-local-ecat-files:nil\n" \
+ "End:\n" \
+ "vim600: syn=xml fen fdm=syntax fdl=2 si\n" \
+ "vim: et tw=78 syn=sgml\n" \
+ "vi: ts=1 sw=1\n" \
+ "-->\n"
+}
+
+{
+ args_max = args_min = optional = i = spec_opt = 0
+ line = $0
+ spec_str = "\""
+
+## php extension must use lower case function names.
+## this will translate any capitalized letter to lowercase
+## and warn the user
+ if (match(func_name,"[A-Z]") != 0) {
+ printf("NOTICE: lower casing function name '%s'\n",func_name)
+ func_name = tolower(func_name)
+ }
+ func_type = gobble(type);
+ func_name = gobble(name);
+
+ if (gobble("\\(")) {
+ if (gobble("\\[")) optional = 1
+ while (arg_type = gobble(type)) {
+ arg_name = gobble(name)
+ if(arg_type == "void") {
+ args_max = 0;
+ args_min = 0;
+ break;
+ } else {
+ argtypes[num_funcs,args_max] = arg_type
+ argnames[num_funcs,args_max] = arg_name
+
+ args_max++
+ if (optional) {
+ if (!spec_opt) {
+ spec_str = spec_str "|"
+ spec_opt = 1
+ }
+ optionals[num_funcs,i] = optional
+ } else {
+ args_min++
+ }
+ spec_str = spec_str spec_map[arg_type]
+
+ if (x = gobble("\\[")) {
+ optional++
+ }
+
+ y = gobble(",")
+ if (!x && y && optional) {
+ grouped_optional_param[num_funcs,i] = 1
+ }
+ i++
+ }
+ }
+ }
+
+# if (x = gobble("\\)")) {
+ gobble("\\]* *\\)")
+ sub(/^[ \t]+/, "", line)
+ fcomments[num_funcs] = line
+# }
+
+ spec_str = spec_str "\""
+
+ funcs[num_funcs] = func_name
+ types[num_funcs] = func_type
+ maxargs[num_funcs] = args_max
+ minargs[num_funcs] = args_min
+ specs[num_funcs] = spec_str
+ spec_opts[num_funcs] = spec_opt
+
+ num_funcs++
+}
+
+END {
+ if (xml) print xmlhead > xmldoc
+ for (i = 0; i < num_funcs; i++) {
+ compareargc = maxargs[i] - minargs[i]
+ closefetch = fetchargs = zvals = xmlparams = funcvals = resources = handleargs = closeopts = ""
+ ints = longs = doubles = strings = bools = zvals = ""
+
+ proto = "/* {{{ proto " types[i] " " funcs[i] "("
+
+ refid = funcs[i]
+ gsub(/_/, "-", refid)
+ xmlstr = " <refentry id=\"function." refid "\">\n" \
+ " <refnamediv>\n" \
+ " <refname>" funcs[i] "</refname>\n" \
+ " <refpurpose>" fcomments[i] "</refpurpose>\n" \
+ " </refnamediv>\n" \
+ " <refsect1>\n" \
+ " <title>Description</title>\n" \
+ " <funcsynopsis>\n" \
+ " <funcprototype>\n" \
+ " <funcdef>" types[i] " <function>" funcs[i] "</function></funcdef>\n"
+
+ if (maxargs[i]>0) {
+ fetchargs = "\tif (zend_parse_parameters("
+ ints = ints "\tint argc = ZEND_NUM_ARGS();\n"
+ fetchargs = fetchargs "argc TSRMLS_CC, " specs[i]
+ } else {
+ fetchargs = fetchargs "\tif (ZEND_NUM_ARGS() != 0) {\n\t\tWRONG_PARAM_COUNT;\n\t}"
+ xmlparams = xmlparams " <void/>\n"
+ }
+
+ for (j = 0; j < maxargs[i]; j++) {
+
+ fetchargs = fetchargs ", "
+
+ fetchargs = fetchargs "&" argnames[i,j]
+ if (argtypes[i,j] == "string") {
+ fetchargs = fetchargs ", &" argnames[i,j] "_len"
+ }
+
+ xmlparams = xmlparams " <paramdef>" argtypes[i,j]
+ if (j > minargs[i]-1) {
+ if (!grouped_optional_param[i,j-1]) {
+ if (j > 0) proto = proto " "
+ proto = proto "["
+ closeopts = closeopts "]"
+ }
+ xmlparams = xmlparams "\n <parameter><optional>" \
+ argnames[i,j] \
+ "</optional></parameter>\n </paramdef>\n"
+ } else {
+ xmlparams = xmlparams \
+ " <parameter>" \
+ argnames[i,j] \
+ "</parameter></paramdef>\n"
+ }
+
+ if (j > 0) proto = proto ", "
+ proto = proto argtypes[i,j] " " argnames[i,j]
+
+ convert(i, j, 1)
+ }
+
+ proto = proto closeopts ")\n " fcomments[i] " */\nPHP_FUNCTION(" funcs[i] ")\n{"
+ if (maxargs[i]>0) {
+ fetchargs = fetchargs ") == FAILURE)" closefetch " \n\t\treturn;\n"
+ }
+ funcvals = strings ints longs doubles bools zvals
+ xmlstr = xmlstr xmlparams \
+ " </funcprototype>\n" \
+ " </funcsynopsis>\n" \
+ " &warn.experimental.func;\n" \
+ " <para>\n" \
+ " &warn.undocumented.func;\n" \
+ " </para>\n" \
+ " </refsect1>\n" \
+ " </refentry>\n"
+
+ print proto > stubfile
+ if (funcvals) print funcvals > stubfile
+ if (fetchargs) print fetchargs > stubfile
+ if (resources) {
+ print resources > stubfile
+ if (!stubs) print "" > extname "/function_warning"
+ }
+ if (!i_know_what_to_do_shut_up_i_dont_need_your_help_mode) {
+ print "\tphp_error(E_WARNING, \"" funcs[i] ": not yet implemented\");" > stubfile
+ }
+ print "}\n/* }}} */\n" > stubfile
+
+ if (stubs) {
+ h_stubs = h_stubs "PHP_FUNCTION(" funcs[i] ");\n"
+ c_stubs = c_stubs "\tPHP_FE(" funcs[i] ",\tNULL)\n"
+ } else {
+ print "PHP_FUNCTION(" funcs[i] ");" > extname "/function_declarations"
+ print "\tPHP_FE(" funcs[i] ",\tNULL)" > extname "/function_entries"
+ }
+
+ if (xml) print xmlstr > xmldoc
+ }
+
+ if (stubs) {
+ print "\n/* ----------------------------------------------------------- */\n" > stubfile
+ print c_stubs > stubfile
+ print "\n/* ----------------------------------------------------------- */\n" > stubfile
+ print h_stubs > stubfile
+ }
+
+ if (xml) print xmlfoot > xmldoc
+}
+
+#
+# Local variables:
+# tab-width: 2
+# c-basic-offset: 2
+# End:
+
diff --git a/ext/skeleton/php_skeleton.h b/ext/skeleton/php_skeleton.h
new file mode 100644
index 0000000000..76ad225754
--- /dev/null
+++ b/ext/skeleton/php_skeleton.h
@@ -0,0 +1,56 @@
+/* __header_here__ */
+
+#ifndef PHP_EXTNAME_H
+#define PHP_EXTNAME_H
+
+extern zend_module_entry extname_module_entry;
+#define phpext_extname_ptr &extname_module_entry
+
+#ifdef PHP_WIN32
+#define PHP_EXTNAME_API __declspec(dllexport)
+#else
+#define PHP_EXTNAME_API
+#endif
+
+#ifdef ZTS
+#include "TSRM.h"
+#endif
+
+PHP_MINIT_FUNCTION(extname);
+PHP_MSHUTDOWN_FUNCTION(extname);
+PHP_RINIT_FUNCTION(extname);
+PHP_RSHUTDOWN_FUNCTION(extname);
+PHP_MINFO_FUNCTION(extname);
+
+PHP_FUNCTION(confirm_extname_compiled); /* For testing, remove later. */
+/* __function_declarations_here__ */
+
+/*
+ Declare any global variables you may need between the BEGIN
+ and END macros here:
+
+ZEND_BEGIN_MODULE_GLOBALS(extname)
+ long global_value;
+ char *global_string;
+ZEND_END_MODULE_GLOBALS(extname)
+*/
+
+/* In every utility function you add that needs to use variables
+ in php_extname_globals, call TSRM_FETCH(); after declaring other
+ variables used by that function, or better yet, pass in TSRMLS_CC
+ after the last function argument and declare your utility function
+ with TSRMLS_DC after the last declared argument. Always refer to
+ the globals in your function as EXTNAME_G(variable). You are
+ encouraged to rename these macros something shorter, see
+ examples in any other php module directory.
+*/
+
+#ifdef ZTS
+#define EXTNAME_G(v) TSRMG(extname_globals_id, zend_extname_globals *, v)
+#else
+#define EXTNAME_G(v) (extname_globals.v)
+#endif
+
+#endif /* PHP_EXTNAME_H */
+
+/* __footer_here__ */
diff --git a/ext/skeleton/skeleton.c b/ext/skeleton/skeleton.c
new file mode 100644
index 0000000000..021b76e789
--- /dev/null
+++ b/ext/skeleton/skeleton.c
@@ -0,0 +1,167 @@
+/* __header_here__ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "php_extname.h"
+
+/* If you declare any globals in php_extname.h uncomment this:
+ZEND_DECLARE_MODULE_GLOBALS(extname)
+*/
+
+/* True global resources - no need for thread safety here */
+static int le_extname;
+
+/* {{{ extname_functions[]
+ *
+ * Every user visible function must have an entry in extname_functions[].
+ */
+function_entry extname_functions[] = {
+ PHP_FE(confirm_extname_compiled, NULL) /* For testing, remove later. */
+ /* __function_entries_here__ */
+ {NULL, NULL, NULL} /* Must be the last line in extname_functions[] */
+};
+/* }}} */
+
+/* {{{ extname_module_entry
+ */
+zend_module_entry extname_module_entry = {
+#if ZEND_MODULE_API_NO >= 20010901
+ STANDARD_MODULE_HEADER,
+#endif
+ "extname",
+ extname_functions,
+ PHP_MINIT(extname),
+ PHP_MSHUTDOWN(extname),
+ PHP_RINIT(extname), /* Replace with NULL if there's nothing to do at request start */
+ PHP_RSHUTDOWN(extname), /* Replace with NULL if there's nothing to do at request end */
+ PHP_MINFO(extname),
+#if ZEND_MODULE_API_NO >= 20010901
+ "0.1", /* Replace with version number for your extension */
+#endif
+ STANDARD_MODULE_PROPERTIES
+};
+/* }}} */
+
+#ifdef COMPILE_DL_EXTNAME
+ZEND_GET_MODULE(extname)
+#endif
+
+/* {{{ PHP_INI
+ */
+/* Remove comments and fill if you need to have entries in php.ini
+PHP_INI_BEGIN()
+ STD_PHP_INI_ENTRY("extname.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_extname_globals, extname_globals)
+ STD_PHP_INI_ENTRY("extname.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_extname_globals, extname_globals)
+PHP_INI_END()
+*/
+/* }}} */
+
+/* {{{ php_extname_init_globals
+ */
+/* Uncomment this function if you have INI entries
+static void php_extname_init_globals(zend_extname_globals *extname_globals)
+{
+ extname_globals->global_value = 0;
+ extname_globals->global_string = NULL;
+}
+*/
+/* }}} */
+
+/* {{{ PHP_MINIT_FUNCTION
+ */
+PHP_MINIT_FUNCTION(extname)
+{
+ /* If you have INI entries, uncomment these lines
+ ZEND_INIT_MODULE_GLOBALS(extname, php_extname_init_globals, NULL);
+ REGISTER_INI_ENTRIES();
+ */
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MSHUTDOWN_FUNCTION
+ */
+PHP_MSHUTDOWN_FUNCTION(extname)
+{
+ /* uncomment this line if you have INI entries
+ UNREGISTER_INI_ENTRIES();
+ */
+ return SUCCESS;
+}
+/* }}} */
+
+/* Remove if there's nothing to do at request start */
+/* {{{ PHP_RINIT_FUNCTION
+ */
+PHP_RINIT_FUNCTION(extname)
+{
+ return SUCCESS;
+}
+/* }}} */
+
+/* Remove if there's nothing to do at request end */
+/* {{{ PHP_RSHUTDOWN_FUNCTION
+ */
+PHP_RSHUTDOWN_FUNCTION(extname)
+{
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MINFO_FUNCTION
+ */
+PHP_MINFO_FUNCTION(extname)
+{
+ php_info_print_table_start();
+ php_info_print_table_header(2, "extname support", "enabled");
+ php_info_print_table_end();
+
+ /* Remove comments if you have entries in php.ini
+ DISPLAY_INI_ENTRIES();
+ */
+}
+/* }}} */
+
+
+/* Remove the following function when you have succesfully modified config.m4
+ so that your module can be compiled into PHP, it exists only for testing
+ purposes. */
+
+/* Every user-visible function in PHP should document itself in the source */
+/* {{{ proto string confirm_extname_compiled(string arg)
+ Return a string to confirm that the module is compiled in */
+PHP_FUNCTION(confirm_extname_compiled)
+{
+ char *arg = NULL;
+ int arg_len, len;
+ char string[256];
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
+ return;
+ }
+
+ len = sprintf(string, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "extname", arg);
+ RETURN_STRINGL(string, len, 1);
+}
+/* }}} */
+/* The previous line is meant for vim and emacs, so it can correctly fold and
+ unfold functions in source code. See the corresponding marks just before
+ function definition, where the functions purpose is also documented. Please
+ follow this convention for the convenience of others editing your code.
+*/
+
+/* __function_stubs_here__ */
+
+/*
+ * 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
+ */
diff --git a/ext/skeleton/skeleton.dsp b/ext/skeleton/skeleton.dsp
new file mode 100644
index 0000000000..5f84019f21
--- /dev/null
+++ b/ext/skeleton/skeleton.dsp
@@ -0,0 +1,113 @@
+# Microsoft Developer Studio Project File - Name="extname" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=extname - Win32 Release_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 "extname.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 "extname.mak" CFG="extname - Win32 Release_TS"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "extname - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "extname - 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)" == "extname - 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 Ignore_Export_Lib 0
+# 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 /I "..\.." /I "..\..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\..\TSRM" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_EXTNAME" /D ZTS=1 /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D ZEND_DEBUG=0 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXTNAME_EXPORTS" /D "COMPILE_DL_EXTNAME" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_EXTNAME=1 /D "LIBZEND_EXPORTS" /FR /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x406 /d "NDEBUG"
+# ADD RSC /l 0x406 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS/extname.dll" /libpath:"..\..\Release_TS" /libpath:"..\..\Release_TS_Inline"
+
+!ELSEIF "$(CFG)" == "extname - Win32 Debug_TS"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Debug_TS"
+# PROP BASE Intermediate_Dir "Debug_TS"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Debug_TS"
+# PROP Intermediate_Dir "Debug_TS"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "..\.." /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_EXTNAME" /D ZTS=1 /YX /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D ZEND_DEBUG=1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXTNAME_EXPORTS" /D "COMPILE_DL_EXTNAME" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_EXTNAME=1 /D "LIBZEND_EXPORTS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x406 /d "NDEBUG"
+# ADD RSC /l 0x406 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts_debug.lib /nologo /dll /machine:I386 /out:"..\..\Debug_TS/extname.dll" /libpath:"..\..\Debug_TS"
+
+!ENDIF
+
+# Begin Target
+
+# Name "extname - Win32 Release_TS"
+# Name "extname - Win32 Debug_TS"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\extname.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\php_extname.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/ext/skeleton/skeleton.php b/ext/skeleton/skeleton.php
new file mode 100644
index 0000000000..12e1e64bb4
--- /dev/null
+++ b/ext/skeleton/skeleton.php
@@ -0,0 +1,19 @@
+<?
+if(!extension_loaded('extname')) {
+ dl('extname.' . PHP_SHLIB_SUFFIX);
+}
+$module = 'extname';
+$functions = get_extension_funcs($module);
+echo "Functions available in the test extension:<br>\n";
+foreach($functions as $func) {
+ echo $func."<br>\n";
+}
+echo "<br>\n";
+$function = 'confirm_' . $module . '_compiled';
+if (extension_loaded($module)) {
+ $str = $function($module);
+} else {
+ $str = "Module $module is not compiled into PHP";
+}
+echo "$str\n";
+?>
diff --git a/ext/skeleton/tests/001.phpt b/ext/skeleton/tests/001.phpt
new file mode 100644
index 0000000000..7ef8472db3
--- /dev/null
+++ b/ext/skeleton/tests/001.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Check for extname presence
+--SKIPIF--
+<?php if (!extension_loaded("extname")) print "skip"; ?>
+--POST--
+--GET--
+--INI--
+--FILE--
+<?php
+echo "extname extension is available";
+/*
+ you can add regression tests for your extension here
+
+ the output of your test code has to be equal to the
+ text in the --EXPECT-- section below for the tests
+ to pass, differences between the output and the
+ expected text are interpreted as failure
+
+ see php4/README.TESTING for further information on
+ writing regression tests
+*/
+?>
+--EXPECT--
+extname extension is available