From: Jan Kneschke Date: Wed, 12 Dec 2001 09:46:27 +0000 (+0000) Subject: added the new PHPDoc extension which transform PHP-Code into a XML X-Git-Tag: ChangeLog~10 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=63a566c65ae31027c091eeb5099f4d6cfe9c596b;p=php added the new PHPDoc extension which transform PHP-Code into a XML representation. The XML output will be used by PHPDoc as it provides more accuracy and speed. --- diff --git a/ext/phpdoc/Makefile.in b/ext/phpdoc/Makefile.in new file mode 100644 index 0000000000..c04c5766fd --- /dev/null +++ b/ext/phpdoc/Makefile.in @@ -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 index 0000000000..0c8da9a4e8 --- /dev/null +++ b/ext/phpdoc/config.m4 @@ -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 index 0000000000..7c6e176717 --- /dev/null +++ b/ext/phpdoc/libs.mk @@ -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 index 0000000000..5b0cdb7853 --- /dev/null +++ b/ext/phpdoc/php_phpdoc.h @@ -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 index 0000000000..8fb390b84b --- /dev/null +++ b/ext/phpdoc/phpdoc.c @@ -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 | + +----------------------------------------------------------------------+ + */ + +#include "php.h" +#include "php_ini.h" +#include "php_phpdoc.h" + + +/* +** +*/ + +/* 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, "<"); + PHPDOC_STRCAT(new_string, buffer); + break; + case '>': + zend_sprintf(buffer, ">"); + PHPDOC_STRCAT(new_string, buffer); + break; + case '"': + zend_sprintf(buffer, """); + PHPDOC_STRCAT(new_string, buffer); + break; + case '&': + zend_sprintf(buffer, "&"); + PHPDOC_STRCAT(new_string, buffer); + break; + case '\'': + zend_sprintf(buffer, "'"); + 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, "\n"); + + PHPDOC_STRCAT(new_string, "\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, ""); + + sprint_xml(new_string, zendtext); + + PHPDOC_STRCAT(new_string, "\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, "",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, "\n"); + st.pos--; + break; + case -T_FUNCTION: + PHPDOC_STRCAT(new_string, "\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, "\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, "\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: + */