]> granicus.if.org Git - php/commitdiff
added the new PHPDoc extension which transform PHP-Code into a XML
authorJan Kneschke <ostborn@php.net>
Wed, 12 Dec 2001 09:46:27 +0000 (09:46 +0000)
committerJan Kneschke <ostborn@php.net>
Wed, 12 Dec 2001 09:46:27 +0000 (09:46 +0000)
representation.

The XML output will be used by PHPDoc as it provides more accuracy and
speed.

ext/phpdoc/Makefile.in [new file with mode: 0644]
ext/phpdoc/config.m4 [new file with mode: 0644]
ext/phpdoc/libs.mk [new file with mode: 0644]
ext/phpdoc/php_phpdoc.h [new file with mode: 0644]
ext/phpdoc/phpdoc.c [new file with mode: 0644]

diff --git a/ext/phpdoc/Makefile.in b/ext/phpdoc/Makefile.in
new file mode 100644 (file)
index 0000000..c04c576
--- /dev/null
@@ -0,0 +1,8 @@
+# $Id$
+
+LTLIBRARY_NAME        = libphpdoc.la
+LTLIBRARY_SOURCES     = phpdoc.c
+LTLIBRARY_SHARED_NAME = phpdoc.la
+LTLIBRARY_SHARED_LIBADD  = $(PHPDOC_SHARED_LIBADD)
+
+include $(top_srcdir)/build/dynlib.mk
diff --git a/ext/phpdoc/config.m4 b/ext/phpdoc/config.m4
new file mode 100644 (file)
index 0000000..0c8da9a
--- /dev/null
@@ -0,0 +1,27 @@
+dnl $Id$
+dnl config.m4 for extension phpdoc
+dnl don't forget to call PHP_EXTENSION(phpdoc)
+
+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(phpdoc, for phpdoc support,
+dnl Make sure that the comment is aligned:
+dnl [  --with-phpdoc             Include phpdoc support])
+
+dnl Otherwise use enable:
+
+PHP_ARG_ENABLE(phpdoc, whether to enable phpdoc support,
+[  --enable-phpdoc           Enable phpdoc support])
+
+if test "$PHP_PHPDOC" != "no"; then
+  dnl If you will not be testing anything external, like existence of
+  dnl headers, libraries or functions in them, just uncomment the 
+  dnl following line and you are ready to go.
+  AC_DEFINE(HAVE_PHPDOC, 1, [ ])
+  dnl Write more examples of tests here...
+  PHP_EXTENSION(phpdoc, $ext_shared)
+fi
diff --git a/ext/phpdoc/libs.mk b/ext/phpdoc/libs.mk
new file mode 100644 (file)
index 0000000..7c6e176
--- /dev/null
@@ -0,0 +1,7 @@
+include $(top_builddir)/config_vars.mk
+LTLIBRARY_OBJECTS = $(LTLIBRARY_SOURCES:.c=.lo) $(LTLIBRARY_OBJECTS_X)
+LTLIBRARY_SHARED_OBJECTS = $(LTLIBRARY_OBJECTS:.lo=.slo)
+$(LTLIBRARY_NAME): $(LTLIBRARY_OBJECTS) $(LTLIBRARY_DEPENDENCIES)
+       $(LINK) $(LTLIBRARY_LDFLAGS) $(LTLIBRARY_OBJECTS) $(LTLIBRARY_LIBADD)
+
+targets = $(LTLIBRARY_NAME)
diff --git a/ext/phpdoc/php_phpdoc.h b/ext/phpdoc/php_phpdoc.h
new file mode 100644 (file)
index 0000000..5b0cdb7
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP version 4.0                                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997, 1998, 1999, 2000 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.               |
+   +----------------------------------------------------------------------+
+   | Authors:                                                             |
+   |                                                                      |
+   +----------------------------------------------------------------------+
+ */
+
+#ifndef PHP_PHPDOC_H
+#define PHP_PHPDOC_H
+
+/* You should tweak config.m4 so this symbol (or some else suitable)
+   gets defined.
+*/
+#if HAVE_PHPDOC
+
+extern zend_module_entry phpdoc_module_entry;
+#define phpext_phpdoc_ptr &phpdoc_module_entry
+
+#ifdef PHP_WIN32
+#define PHP_PHPDOC_API __declspec(dllexport)
+#else
+#define PHP_PHPDOC_API
+#endif
+
+PHP_MINIT_FUNCTION(phpdoc);
+PHP_MSHUTDOWN_FUNCTION(phpdoc);
+PHP_RINIT_FUNCTION(phpdoc);
+PHP_RSHUTDOWN_FUNCTION(phpdoc);
+PHP_MINFO_FUNCTION(phpdoc);
+
+PHP_FUNCTION(confirm_phpdoc_compiled); /* For testing, remove later. */
+PHP_FUNCTION(phpdoc_xml_from_string);
+
+/* 
+       Declare any global variables you may need between the BEGIN
+       and END macros here:     
+
+ZEND_BEGIN_MODULE_GLOBALS(phpdoc)
+       int global_variable;
+ZEND_END_MODULE_GLOBALS(phpdoc)
+*/
+
+/* In every function that needs to use variables in php_phpdoc_globals,
+   do call PHPDOCLS_FETCH(); after declaring other variables used by
+   that function, and always refer to them as PHPDOCG(variable).
+   You are encouraged to rename these macros something shorter, see
+   examples in any other php module directory.
+*/
+
+#ifdef ZTS
+#define PHPDOCG(v) (phpdoc_globals->v)
+#define PHPDOCLS_FETCH() php_phpdoc_globals *phpdoc_globals = ts_resource(phpdoc_globals_id)
+#else
+#define PHPDOCG(v) (phpdoc_globals.v)
+#define PHPDOCLS_FETCH()
+#endif
+
+#else
+
+#define phpext_phpdoc_ptr NULL
+
+#endif
+
+#endif /* PHP_PHPDOC_H */
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/ext/phpdoc/phpdoc.c b/ext/phpdoc/phpdoc.c
new file mode 100644 (file)
index 0000000..8fb390b
--- /dev/null
@@ -0,0 +1,665 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP version 4.0                                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997, 1998, 1999, 2000 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.               |
+   +----------------------------------------------------------------------+
+   | Authors:                                                             |
+   |   Jan Kneschke <jan.kneschke@phpdoc.de>                              |
+   +----------------------------------------------------------------------+
+ */
+
+#include "php.h"
+#include "php_ini.h"
+#include "php_phpdoc.h"
+
+
+/*
+** <!-- 
+** taken from zend_language_scanner.c
+** perhaps this a LICENSE CONFLICT, don't know.
+*/
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+typedef unsigned int yy_size_t;
+struct yy_buffer_state
+       {
+       FILE *yy_input_file;
+       char *yy_ch_buf;                /* input buffer */
+       char *yy_buf_pos;              /* current position in input buffer */
+       /* Size of input buffer in bytes, not including room for EOB
+        * characters.
+        */
+       yy_size_t yy_buf_size;
+       /* Number of characters read into yy_ch_buf, not including EOB
+        * characters.
+        */
+       int yy_n_chars;
+       /* Whether we "own" the buffer - i.e., we know we created it,
+        * and can realloc() it to grow it, and should free() it to
+        * delete it.
+        */
+       int yy_is_our_buffer;
+       /* Whether this is an "interactive" input source; if so, and
+        * if we're using stdio for input, then we want to use getc()
+        * instead of fread(), to make sure we stop fetching input after
+        * each newline.
+        */
+       int yy_is_interactive;
+       /* Whether we're considered to be at the beginning of a line.
+        * If so, '^' rules will be active on the next match, otherwise
+        * not.
+        */
+       int yy_at_bol;
+       /* Whether to try to fill the input buffer when we reach the
+        * end of it.
+        */
+       int yy_fill_buffer;
+       int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+       /* When an EOF's been seen but there's still some text to process
+        * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+        * shouldn't try reading from the input source any more.  We might
+        * still have a bunch of tokens to match, though, because of
+        * possible backing-up.
+        *
+        * When we actually see the EOF, we change the status to "new"
+        * (via yyrestart()), so that the user can continue scanning by
+        * just pointing yyin at a new input file.
+        */
+#define YY_BUFFER_EOF_PENDING 2
+       };
+
+#include "zend.h"
+#include "zend_language_scanner.h"
+#include "zend_language_parser.h"
+
+#ifndef ZTS
+extern char *zendtext;
+extern int zendleng;
+#else
+#define zendtext ((char *) zend_get_zendtext(CLS_C))
+#define zendleng zend_get_zendleng(CLS_C)
+#endif
+
+/*
+** -->
+*/
+
+/* You should tweak config.m4 so this symbol (or some else suitable)
+   gets defined.
+*/
+#if HAVE_PHPDOC
+
+/* If you declare any globals in php_phpdoc.h uncomment this:
+ZEND_DECLARE_MODULE_GLOBALS(phpdoc)
+*/
+
+/* True global resources - no need for thread safety here */
+static int le_phpdoc;
+
+/* Every user visible function must have an entry in phpdoc_functions[].
+*/
+function_entry phpdoc_functions[] = {
+       PHP_FE(confirm_phpdoc_compiled, NULL)           /* For testing, remove later. */
+       PHP_FE(phpdoc_xml_from_string, NULL)
+       {NULL, NULL, NULL}      /* Must be the last line in phpdoc_functions[] */
+};
+
+zend_module_entry phpdoc_module_entry = {
+       "phpdoc",
+       phpdoc_functions,
+       PHP_MINIT(phpdoc),
+       PHP_MSHUTDOWN(phpdoc),
+       PHP_RINIT(phpdoc),              /* Replace with NULL if there's nothing to do at request start */
+       PHP_RSHUTDOWN(phpdoc),  /* Replace with NULL if there's nothing to do at request end */
+       PHP_MINFO(phpdoc),
+       STANDARD_MODULE_PROPERTIES
+};
+
+#ifdef COMPILE_DL_PHPDOC
+ZEND_GET_MODULE(phpdoc)
+#endif
+
+/* Remove comments and fill if you need to have entries in php.ini
+PHP_INI_BEGIN()
+PHP_INI_END()
+*/
+
+PHP_MINIT_FUNCTION(phpdoc)
+{
+/* Remove comments if you have entries in php.ini
+       REGISTER_INI_ENTRIES();
+*/
+       return SUCCESS;
+}
+
+PHP_MSHUTDOWN_FUNCTION(phpdoc)
+{
+/* Remove comments if you have entries in php.ini
+       UNREGISTER_INI_ENTRIES();
+*/
+       return SUCCESS;
+}
+
+/* Remove if there's nothing to do at request start */
+PHP_RINIT_FUNCTION(phpdoc)
+{
+       return SUCCESS;
+}
+
+/* Remove if there's nothing to do at request end */
+PHP_RSHUTDOWN_FUNCTION(phpdoc)
+{
+       return SUCCESS;
+}
+
+PHP_MINFO_FUNCTION(phpdoc)
+{
+       php_info_print_table_start();
+       php_info_print_table_header(2, "phpdoc support", "enabled");
+       php_info_print_table_row(2, "PHPDoc Version", "IPv6" );
+       php_info_print_table_end();
+
+       /* Remove comments if you have entries in php.ini
+       DISPLAY_INI_ENTRIES();
+       */
+}
+
+/* Every user-visible function in PHP should document itself in the source */
+/* {{{ proto string confirm_phpdoc_compiled(string arg)
+   Return a string to confirm that the module is compiled in */
+
+PHP_FUNCTION(confirm_phpdoc_compiled)
+{
+       zval **arg;
+       int len;
+       char string[256];
+
+       if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+
+       convert_to_string_ex(arg);
+
+       len = sprintf(string, "Congratulations, you have successfully modified ext/phpdoc/config.m4, module %s is compiled into PHP", Z_STRVAL_PP(arg));
+       RETURN_STRINGL(string, len, 1);
+}
+/* }}} */
+
+
+
+
+
+
+
+int find_something(int *stack, int stack_pos) {
+#if 0
+       int i = stack_pos -1;
+
+       zend_printf("L:%d:",i);
+       for (; i >= 0; i--) {
+               zend_printf("[%d]",stack[i]);
+       }
+#endif
+       return (stack_pos > 0) ? stack[stack_pos-1] : -1;
+}
+
+#define PHPDOC_STRCAT(x,y) \
+       x->value.str.len += strlen(y); \
+       if (x->value.str.val != empty_string) {\
+               x->value.str.val = erealloc(x->value.str.val, x->value.str.len+1); \
+               strcat(x->value.str.val, y);\
+       } else {\
+               x->value.str.val = emalloc(x->value.str.len+1); \
+               strcpy(x->value.str.val, y);\
+       }
+
+void sprint_xml(zval *new_string, const char *s) {
+       char buffer[32];
+
+       while (*s) {
+               switch(*s) {
+                       case '<':
+                               zend_sprintf(buffer, "&lt;");
+                               PHPDOC_STRCAT(new_string, buffer);
+                               break;
+                       case '>':
+                               zend_sprintf(buffer, "&gt;");
+                               PHPDOC_STRCAT(new_string, buffer);
+                               break;
+                       case '"':
+                               zend_sprintf(buffer, "&quot;");
+                               PHPDOC_STRCAT(new_string, buffer);
+                               break;
+                       case '&':
+                               zend_sprintf(buffer, "&amp;");
+                               PHPDOC_STRCAT(new_string, buffer);
+                               break;
+                       case '\'':
+                               zend_sprintf(buffer, "&apos;");
+                               PHPDOC_STRCAT(new_string, buffer);
+                               break;
+                       default:
+                               zend_sprintf(buffer, "%c",*s);
+                               PHPDOC_STRCAT(new_string, buffer);
+               }
+               s++;
+       }
+}
+
+
+#define T_FUNCTION_PARAM               INT_MAX-1
+#define T_FUNCTION_PARAM_DEFAULT       INT_MAX-2
+#define T_FUNCTION_PARAM_LIST          INT_MAX-3
+#define T_BLOCK                                INT_MAX-4
+
+typedef struct {
+       int     *stack;
+       int     pos;
+       int     size;
+       int     increment;
+} phpdoc_stack;
+
+zval *gen_xml(int debug)
+{
+       zval token;
+       int token_type;
+       
+       phpdoc_stack st;
+       
+       zval *new_string;
+       
+       char buffer[256];
+       
+       CLS_FETCH();
+       
+       MAKE_STD_ZVAL(new_string);
+       ZVAL_EMPTY_STRING(new_string);
+       
+       /* init the stack */
+       st.size         = 256;
+       st.increment    = 128;
+       st.pos          = 0;
+       st.stack        = emalloc(sizeof(int) * st.size);
+
+       PHPDOC_STRCAT(new_string, "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n");
+       
+       PHPDOC_STRCAT(new_string, "<php>\n");
+
+       st.stack[0] = -1; 
+       
+       token.type = 0;
+       while ((token_type=CG(lang_scanner).lex_scan(&token CLS_CC))) {
+               if (debug)
+                       zend_printf("// %s(%d)\n",zendtext, token_type);
+                       
+               switch (token_type) {
+               case T_INCLUDE:
+                       PHPDOC_STRCAT(new_string, "<uses type=\"include\" file=\"");
+                       st.stack[st.pos++] = token_type;
+                       break;
+               case T_INCLUDE_ONCE:
+                       PHPDOC_STRCAT(new_string, "<uses type=\"include once\" file=\"");
+                       st.stack[st.pos++] = token_type;
+                       break;
+               case T_REQUIRE:
+                       PHPDOC_STRCAT(new_string, "<uses type=\"require\" file=\"");
+                       st.stack[st.pos++] = token_type;
+                       break;
+               case T_REQUIRE_ONCE:
+                       PHPDOC_STRCAT(new_string, "<uses type=\"require once\" file=\"");
+                       st.stack[st.pos++] = token_type;
+                       break;
+               case T_CLASS:
+                       PHPDOC_STRCAT(new_string, "<class ");
+                       st.stack[st.pos++] = token_type;
+                       break;
+               case T_FUNCTION:
+                       PHPDOC_STRCAT(new_string, "<function ");
+                       st.stack[st.pos++] = token_type;
+                       break;
+               case T_VAR:
+                       PHPDOC_STRCAT(new_string, "<variable ");
+                       st.stack[st.pos++] = token_type;
+                       break;
+               case T_GLOBAL:
+                       st.stack[st.pos++] = token_type;
+                       break;
+               case T_ML_COMMENT:
+               case T_COMMENT:
+                       PHPDOC_STRCAT(new_string, "<comment>");
+                       
+                       sprint_xml(new_string, zendtext);
+                       
+                       PHPDOC_STRCAT(new_string, "</comment>\n");
+                       break;
+               case T_EXTENDS:
+                       switch(find_something(st.stack, st.pos)) {
+                       case T_CLASS:
+                               st.stack[st.pos++] = token_type;
+                               break;
+                       default:
+                               zend_printf("ALARM: extends w/o class\n");
+                               break;
+                       }
+                       break;
+               case T_VARIABLE:
+                       switch(find_something(st.stack, st.pos)) {
+                       case T_VAR:
+                               zend_sprintf(buffer, " name=\"%s\"", zendtext);
+                               PHPDOC_STRCAT(new_string, buffer);
+                               break;
+                       case -T_FUNCTION:
+                               st.stack[st.pos++] = token_type;
+                               break;
+                       case T_FUNCTION_PARAM_LIST:
+                               st.stack[st.pos++] = T_FUNCTION_PARAM;
+                               zend_sprintf(buffer, "<args name=\"%s\"", zendtext);
+                               PHPDOC_STRCAT(new_string, buffer);
+                               break;
+                       case T_GLOBAL:
+                               zend_sprintf(buffer, "<global name=\"%s\"/>",zendtext);
+                               PHPDOC_STRCAT(new_string, buffer);
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+                       
+               case T_STRING:
+                       switch(find_something(st.stack, st.pos)) {
+                       case T_CLASS:
+                       case T_FUNCTION:
+                       case T_VAR:
+                               zend_sprintf(buffer, " name=\"%s\"", zendtext);
+                               PHPDOC_STRCAT(new_string, buffer);
+                               break;
+                       case T_EXTENDS:
+                               zend_sprintf(buffer, " extends=\"%s\"", zendtext);
+                               PHPDOC_STRCAT(new_string, buffer);
+                               st.pos--;
+                               break;
+                       case T_INCLUDE:
+                       case T_INCLUDE_ONCE:
+                       case T_REQUIRE:
+                       case T_REQUIRE_ONCE:
+                               PHPDOC_STRCAT(new_string, zendtext);
+                               break;
+                       }
+                       break;
+               case T_DNUMBER:
+                       switch(find_something(st.stack, st.pos)) {
+                       case T_FUNCTION_PARAM_DEFAULT:
+                               PHPDOC_STRCAT(new_string, zendtext);
+                               PHPDOC_STRCAT(new_string, "\"");
+                               st.pos--;
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+               case T_LNUMBER:
+                       switch(find_something(st.stack, st.pos)) {
+                       case T_FUNCTION_PARAM_DEFAULT:
+                               PHPDOC_STRCAT(new_string, zendtext);
+                               PHPDOC_STRCAT(new_string, "\"");
+                               st.pos--;
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+               case '-':
+                       switch(find_something(st.stack, st.pos)) {
+                       case T_FUNCTION_PARAM_DEFAULT:
+                               /* a DNUMBER or LNUMBER will follow */
+                               PHPDOC_STRCAT(new_string, zendtext);
+                               
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+               case '{':
+                       switch (find_something(st.stack, st.pos)) {
+                       case T_CLASS:
+                       case T_FUNCTION:
+                               PHPDOC_STRCAT(new_string, ">");
+                               st.stack[st.pos-1] = -st.stack[st.pos-1];
+                               break;
+                       case T_FUNCTION_PARAM_LIST:
+                               st.pos--;
+                               
+                               /* and finish the function-head */
+                               st.stack[st.pos-1] = -st.stack[st.pos-1];
+                               break;
+                       default:
+                               st.stack[st.pos++] = T_BLOCK;
+                               break;
+                       }
+                       break;
+               case '}':
+                       switch (find_something(st.stack, st.pos)) {
+                       case -T_CLASS:
+                               PHPDOC_STRCAT(new_string, "</class>\n");
+                               st.pos--;
+                               break;
+                       case -T_FUNCTION:
+                               PHPDOC_STRCAT(new_string, "</function>\n");
+                               st.pos--;
+                               break;
+                       case T_BLOCK:
+                               st.pos--;
+                               break;
+                       }
+                       break;
+               case '(':
+                       switch (find_something(st.stack, st.pos)) {
+                       case T_FUNCTION:
+                               /* terminate the function-head */
+                               PHPDOC_STRCAT(new_string, ">");
+                               st.stack[st.pos++] = T_FUNCTION_PARAM_LIST;
+                               break;
+                       }
+                       break;
+               case ')':
+                       switch (find_something(st.stack, st.pos)) {
+                       case T_FUNCTION_PARAM:
+                               /* remove the param-list from the st.stack */
+                               PHPDOC_STRCAT(new_string, "/>");
+                               st.pos--;
+                               break;
+                       case T_INCLUDE:
+                       case T_INCLUDE_ONCE:
+                       case T_REQUIRE:
+                       case T_REQUIRE_ONCE:
+                               zend_sprintf(buffer, "\"/>\n");
+                               PHPDOC_STRCAT(new_string, buffer);
+                               st.pos--;
+                               break;
+                       }
+                       break;
+               case '=':
+                       switch (find_something(st.stack, st.pos)) {
+                       case T_VAR:
+                               zend_sprintf(buffer, ">");
+                               PHPDOC_STRCAT(new_string, buffer);
+                               st.stack[st.pos-1] = -st.stack[st.pos-1];
+                               break;
+                       case T_FUNCTION_PARAM:
+                               zend_sprintf(buffer, " default=\"");
+                               PHPDOC_STRCAT(new_string, buffer);
+                               st.stack[st.pos++] = T_FUNCTION_PARAM_DEFAULT;
+                               
+                               break;
+                       }
+                       break;
+               case ';':
+                       switch (find_something(st.stack, st.pos)) {
+                       case T_VAR:
+                               zend_sprintf(buffer, ">");
+                               PHPDOC_STRCAT(new_string, buffer);
+                       case -T_VAR:
+                               zend_sprintf(buffer, "</variable>\n");
+                               PHPDOC_STRCAT(new_string, buffer);
+                               st.pos--;
+                               break;
+                       case T_GLOBAL:
+                       case T_VARIABLE:
+                               st.pos--;
+                               break;
+                       case T_INCLUDE:
+                       case T_INCLUDE_ONCE:
+                       case T_REQUIRE:
+                       case T_REQUIRE_ONCE:
+                               zend_sprintf(buffer, "\"/>\n");
+                               PHPDOC_STRCAT(new_string, buffer);
+                               st.pos--;
+                               break;
+                       }
+                       break;
+               case ',':
+               case T_ARRAY:
+                       switch (find_something(st.stack, st.pos)) {
+                       case T_FUNCTION_PARAM:
+                               zend_sprintf(buffer, "/>");
+                               PHPDOC_STRCAT(new_string, buffer);
+                               st.pos--;
+                               break;
+                       }
+               case T_CONSTANT_ENCAPSED_STRING:
+                       switch (find_something(st.stack, st.pos)) {
+                       case T_INCLUDE:
+                       case T_INCLUDE_ONCE:
+                       case T_REQUIRE:
+                       case T_REQUIRE_ONCE:
+                               sprint_xml(new_string, zendtext);
+                               break;
+                       case T_FUNCTION_PARAM_DEFAULT:
+                               sprint_xml(new_string, zendtext);
+                               PHPDOC_STRCAT(new_string, "\"");
+                               st.pos--;
+                               break;
+                       }
+                       break;
+               case '.':
+                       switch (find_something(st.stack, st.pos)) {
+                       case T_INCLUDE:
+                       case T_INCLUDE_ONCE:
+                       case T_REQUIRE:
+                       case T_REQUIRE_ONCE:
+                               zend_sprintf(buffer, "%s",zendtext);
+                               PHPDOC_STRCAT(new_string, buffer);
+                               break;
+                       }
+                       break;
+               default:
+                       break;
+               }
+               
+               if (st.pos >= st.size - 5) {
+                       st.size += st.increment;
+                       st.stack = erealloc(st.stack, st.size);
+               }
+               
+               if (st.pos < 0) {
+                       char *c = NULL;
+                       
+                       /* i don't really know how to handle it. gooing down hard seem to be to best way */
+                       
+                       *c = 'V';
+               }
+               
+               if (token_type == T_END_HEREDOC) {
+                       zend_bool has_semicolon=(strchr(token.value.str.val, ';')?1:0);
+
+                       efree(token.value.str.val);
+                       if (has_semicolon) {
+                               lex_scan(&token CLS_CC);
+                       }
+               }
+               token.type = 0;
+       }
+       
+       efree(st.stack);
+       
+       PHPDOC_STRCAT(new_string, "</php>\n");
+       
+       zval_copy_ctor(new_string);
+       return new_string;
+}
+
+/* {{{ proto string phpdoc_xml_from_string(string arg)
+   Generates XML for PHPDoc from a usersupplied string */
+
+PHP_FUNCTION(phpdoc_xml_from_string)
+{
+       zval **arg;
+       zend_lex_state original_lex_state;
+       
+#ifdef ZTS
+       istrstream *input_stream;
+#endif
+
+       CLS_FETCH();
+
+       if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       
+       convert_to_string_ex(arg);
+
+       CG(lang_scanner).save_lexical_state(&original_lex_state CLS_CC);
+       
+#ifndef ZTS
+       if (prepare_string_for_scanning(*arg, "dummy.php")==FAILURE) {
+#else
+       if (prepare_string_for_scanning(*arg, &input_stream, "dummy.php" CLS_CC)==FAILURE) {
+#endif
+               RETURN_EMPTY_STRING();
+       }
+#if 1
+       *return_value = *gen_xml(0);
+#else
+       MAKE_STD_ZVAL(return_value);
+       ZVAL_EMPTY_STRING(return_value);
+#endif
+       CG(lang_scanner).restore_lexical_state(&original_lex_state CLS_CC);
+#ifdef ZTS
+       delete input_stream;
+#endif
+
+       zval_copy_ctor(return_value);
+       return;
+       
+}
+/* }}} */
+
+
+#endif /* HAVE_PHPDOC */
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */