diff --git a/package.xml b/package.xml index d35711d..8202913 100644 --- a/package.xml +++ b/package.xml @@ -17,8 +17,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> 2011-04-26 - 0.9.0 - 0.9.0 + 0.1.0 + 0.1.0 beta diff --git a/php_svm.h b/php_svm.h index a171988..6041f3e 100644 --- a/php_svm.h +++ b/php_svm.h @@ -19,7 +19,7 @@ # define _PHP_SVM_H_ #define PHP_SVM_EXTNAME "svm" -#define PHP_SVM_EXTVER "@PACKAGE_VERSION@" +#define PHP_SVM_EXTVER "0.1.0-dev" #ifdef HAVE_CONFIG_H # include "config.h" @@ -30,13 +30,6 @@ #endif #include "php.h" -#include - -ZEND_BEGIN_MODULE_GLOBALS(svm) - zend_bool test; -ZEND_END_MODULE_GLOBALS(svm) - -ZEND_EXTERN_MODULE_GLOBALS(svm) #ifdef ZTS # define SVM_G(v) TSRMG(svm_globals_id, zend_svm_globals *, v) @@ -44,27 +37,6 @@ ZEND_EXTERN_MODULE_GLOBALS(svm) # define SVM_G(v) (svm_globals.v) #endif -typedef struct _php_svm_object { - zend_object zo; - /* hold the SVM parameters */ - struct svm_parameter param; - - /* Store the last error message here */ - char last_error[512]; - -} php_svm_object; - -typedef struct _php_svm_model_object { - zend_object zo; - - /* Hold the training data */ - struct svm_node *x_space; - - /* hold the model generated by training, or to be used for classifying*/ - struct svm_model *model; - -} php_svm_model_object; - extern zend_module_entry svm_module_entry; #define phpext_svm_ptr &svm_module_entry diff --git a/php_svm_internal.h b/php_svm_internal.h new file mode 100644 index 0000000..25ca7ff --- /dev/null +++ b/php_svm_internal.h @@ -0,0 +1,47 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 / svm | + +----------------------------------------------------------------------+ + | Copyright (c) 2010 Ian Barber | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.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: Ian Barber | + +----------------------------------------------------------------------+ +*/ + +#ifndef _PHP_SVM_INTERNAL_H_ +# define _PHP_SVM_INTERNAL_H_ + +#include + +typedef struct _php_svm_object { + zend_object zo; + /* hold the SVM parameters */ + struct svm_parameter param; + + /* Store the last error message here */ + char last_error[512]; + +} php_svm_object; + +typedef struct _php_svm_model_object { + zend_object zo; + + /* Hold the training data */ + struct svm_node *x_space; + + /* hold the model generated by training, or to be used for classifying*/ + struct svm_model *model; + +} php_svm_model_object; + +#endif /* _PHP_SVM_INTERNAL_H_ */ + + diff --git a/svm.c b/svm.c index 9e990af..2d79800 100644 --- a/svm.c +++ b/svm.c @@ -17,31 +17,35 @@ */ #include "php_svm.h" +#include "php_svm_internal.h" #include "php_ini.h" /* needed for 5.2 */ #include "Zend/zend_exceptions.h" #include "ext/standard/info.h" -zend_class_entry *php_svm_sc_entry; -zend_class_entry *php_svm_model_sc_entry; -zend_class_entry *php_svm_exception_sc_entry; +static zend_class_entry *php_svm_sc_entry; +static zend_class_entry *php_svm_model_sc_entry; +static zend_class_entry *php_svm_exception_sc_entry; static zend_object_handlers svm_object_handlers; static zend_object_handlers svm_model_object_handlers; +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +#endif + + #define SVM_MAX_LINE_SIZE 4096 #define SVM_THROW(message, code) \ zend_throw_exception(php_svm_exception_sc_entry, message, (long)code TSRMLS_CC); \ return; - + +#define SVM_ERROR_MSG_SIZE 512 #define SVM_THROW_LAST_ERROR(fallback, code) \ zend_throw_exception(php_svm_exception_sc_entry, (strlen(intern->last_error) ? intern->last_error : fallback), (long)code TSRMLS_CC); \ - memset(intern->last_error, 0, 512); \ + memset(intern->last_error, 0, SVM_ERROR_MSG_SIZE); \ return; -ZEND_DECLARE_MODULE_GLOBALS(svm); - -#define SVM_SET_ERROR_MSG(intern, ...) snprintf(intern->last_error, 512, __VA_ARGS__); - typedef enum SvmLongAttribute { SvmLongAttributeMin = 100, phpsvm_svm_type, @@ -67,12 +71,12 @@ typedef enum SvmDoubleAttribute { /* ---- START HELPER FUNCS ---- */ -void print_null(const char *s) {} +static void print_null(const char *s) {} static zend_bool php_svm_set_double_attribute(php_svm_object *intern, SvmDoubleAttribute name, double value) { if (name >= SvmDoubleAttributeMax) { - return 0; + return FALSE; } switch (name) { @@ -102,16 +106,16 @@ static zend_bool php_svm_set_double_attribute(php_svm_object *intern, SvmDoubleA intern->param.weight = &value; break; default: - return 0; + return FALSE; } - return 1; + return TRUE; } static zend_bool php_svm_set_long_attribute(php_svm_object *intern, SvmLongAttribute name, long value) { if (name >= SvmLongAttributeMax) { - return 0; + return FALSE; } switch (name) { @@ -121,7 +125,7 @@ static zend_bool php_svm_set_long_attribute(php_svm_object *intern, SvmLongAttri value != ONE_CLASS && value != EPSILON_SVR && value != NU_SVR ) { - return 0; + return FALSE; } intern->param.svm_type = (int)value; break; @@ -131,7 +135,7 @@ static zend_bool php_svm_set_long_attribute(php_svm_object *intern, SvmLongAttri value != RBF && value != SIGMOID && value != PRECOMPUTED ) { - return 0; + return FALSE; } intern->param.kernel_type = (int)value; break; @@ -145,10 +149,10 @@ static zend_bool php_svm_set_long_attribute(php_svm_object *intern, SvmLongAttri intern->param.probability = value; break; default: - return 0; + return FALSE; } - return 1; + return TRUE; } /** {{{ zend_bool php_svm_stream_to_array(php_svm_object *intern, php_stream *stream, zval *retval TSRMLS_DC) @@ -172,8 +176,8 @@ static zend_bool php_svm_stream_to_array(php_svm_object *intern, php_stream *str label = php_strtok_r(ptr, " \t", &l); if (!label) { - SVM_SET_ERROR_MSG(intern, "Incorrect data format on line %d", line); - return 0; + snprintf(intern->last_error, SVM_ERROR_MSG_SIZE, "Incorrect data format on line %d", line); + return FALSE; } /* The line array */ @@ -197,8 +201,9 @@ static zend_bool php_svm_stream_to_array(php_svm_object *intern, php_stream *str idx = php_strtok_r(NULL, ":", &l); value = php_strtok_r(NULL, " \t", &l); - if (!value) + if (!value) { break; + } /* Make zvals and convert to correct types */ MAKE_STD_ZVAL(pz_idx); @@ -217,7 +222,7 @@ static zend_bool php_svm_stream_to_array(php_svm_object *intern, php_stream *str line++; } } - return 1; + return TRUE; } /* }}} */ @@ -234,8 +239,9 @@ static int _php_count_values(zval *array) zend_hash_get_current_data(Z_ARRVAL_P(array), (void **) &ppzval) == SUCCESS; zend_hash_move_forward(Z_ARRVAL_P(array))) { - if (Z_TYPE_PP(ppzval) == IS_ARRAY) + if (Z_TYPE_PP(ppzval) == IS_ARRAY) { values += zend_hash_num_elements(Z_ARRVAL_PP(ppzval)); + } } return values; } @@ -245,14 +251,17 @@ static int _php_count_values(zval *array) Free the generated problem. */ static void php_svm_free_problem(struct svm_problem *problem) { - if (problem->x) + if (problem->x) { efree(problem->x); + } - if (problem->y) + if (problem->y) { efree(problem->y); + } - if (problem) + if (problem) { efree(problem); + } } /* }}} */ @@ -376,7 +385,7 @@ static struct svm_problem* php_svm_read_array(php_svm_object *intern, php_svm_mo return_error: php_svm_free_problem(problem); if (err_msg) { - SVM_SET_ERROR_MSG(intern, err_msg); + snprintf(intern->last_error, SVM_ERROR_MSG_SIZE, err_msg); } return NULL; @@ -388,22 +397,22 @@ Train based on a libsvm problem structure */ static zend_bool php_svm_train(php_svm_object *intern, php_svm_model_object *intern_model, struct svm_problem *problem) { - char *err_msg = NULL; + const char *err_msg = NULL; err_msg = svm_check_parameter(problem, &(intern->param)); if (err_msg) { - SVM_SET_ERROR_MSG(intern, err_msg); - return 0; + snprintf(intern->last_error, SVM_ERROR_MSG_SIZE, err_msg); + return FALSE; } intern_model->model = svm_train(problem, &(intern->param)); /* Failure ? */ if (!intern_model->model) { - SVM_SET_ERROR_MSG(intern, "Failed to train using the data"); - return 0; + snprintf(intern->last_error, SVM_ERROR_MSG_SIZE, "Failed to train using the data"); + return FALSE; } - return 1; + return TRUE; } /* }}} */ @@ -434,16 +443,16 @@ static zval* php_svm_get_data_from_param(php_svm_object *intern, zval *zparam TS break; default: - SVM_SET_ERROR_MSG(intern, "Incorrect parameter type, expecting string, stream or an array"); - return 0; + snprintf(intern->last_error, SVM_ERROR_MSG_SIZE, "Incorrect parameter type, expecting string, stream or an array"); + return FALSE; break; } /* If we got stream then read it in */ if (need_read) { if (!stream) { - SVM_SET_ERROR_MSG(intern, "Failed to open the data file"); - return 0; + snprintf(intern->last_error, SVM_ERROR_MSG_SIZE, "Failed to open the data file"); + return FALSE; } MAKE_STD_ZVAL(data); @@ -455,8 +464,8 @@ static zval* php_svm_get_data_from_param(php_svm_object *intern, zval *zparam TS if (our_stream) { php_stream_close(stream); } - SVM_SET_ERROR_MSG(intern, "Failed to read the data"); - return 0; + snprintf(intern->last_error, SVM_ERROR_MSG_SIZE, "Failed to read the data"); + return FALSE; } } else { data = zparam; @@ -484,7 +493,7 @@ PHP_METHOD(svm, __construct) php_svm_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { - return; + SVM_THROW("Invalid parameters passed to constructor", 154); } intern = (php_svm_object *)zend_object_store_get_object(getThis() TSRMLS_CC); @@ -786,11 +795,12 @@ PHP_METHOD(svmmodel, __construct) int filename_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &filename, &filename_len) == FAILURE) { - return; + SVM_THROW("Invalid parameters passed to constructor", 154); } - if (!filename) + if (!filename) { return; + } intern = (php_svm_model_object *)zend_object_store_get_object(getThis() TSRMLS_CC); intern->model = svm_load_model(filename); @@ -882,7 +892,7 @@ PHP_METHOD(svmmodel, predict) } /* need 1 extra to indicate the end */ - x = emalloc((array_count + 1) *sizeof(struct svm_node)); + x = safe_emalloc((array_count + 1), sizeof(struct svm_node), 0); i = 0; zval temp; @@ -919,11 +929,6 @@ PHP_METHOD(svmmodel, predict) /* ---- END SVMMODEL ---- */ -static void php_svm_init_globals(zend_svm_globals *svm_globals) -{ - /* No globals */ -} - static void php_svm_object_free_storage(void *object TSRMLS_DC) { php_svm_object *intern = (php_svm_object *)object; @@ -1070,8 +1075,6 @@ static function_entry php_svm_model_class_methods[] = PHP_MINIT_FUNCTION(svm) { zend_class_entry ce; - ZEND_INIT_MODULE_GLOBALS(svm, php_svm_init_globals, NULL); - memcpy(&svm_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); memcpy(&svm_model_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); @@ -1090,8 +1093,6 @@ PHP_MINIT_FUNCTION(svm) php_svm_exception_sc_entry->ce_flags |= ZEND_ACC_FINAL; /* Redirect the lib svm output */ - //extern void (*svm_print_string) (const char *); - //svm_print_string = &print_null; svm_set_print_string_function(&print_null); #define SVM_REGISTER_CONST_LONG(const_name, value) \ diff --git a/tests/012_baddata.phpt b/tests/012_baddata.phpt new file mode 100644 index 0000000..6eaed48 --- /dev/null +++ b/tests/012_baddata.phpt @@ -0,0 +1,17 @@ +--TEST-- +Test handling a bad filename +--SKIPIF-- + +--FILE-- +train(dirname(__FILE__) . '/baddata.scale'); +} catch(SVMException $e) { + echo "got exception"; +} +?> +--EXPECT-- +got exception diff --git a/tests/baddata.scale b/tests/baddata.scale new file mode 100644 index 0000000..0aa6fb5 --- /dev/null +++ b/tests/baddata.scale @@ -0,0 +1 @@ +test data \ No newline at end of file