/* +----------------------------------------------------------------------+ | 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: Vlad Krupin | +----------------------------------------------------------------------+ */ /* $Id$ */ #define IS_EXT_MODULE #include "php.h" #include #include #include #if HAVE_PSPELL #include "php_pspell.h" #include #include "ext/standard/info.h" #define PSPELL_FAST 1L #define PSPELL_NORMAL 2L #define PSPELL_BAD_SPELLERS 3L #define PSPELL_SPEED_MASK_INTERNAL 3L #define PSPELL_RUN_TOGETHER 8L function_entry pspell_functions[] = { PHP_FE(pspell_new, NULL) PHP_FE(pspell_new_personal, NULL) PHP_FE(pspell_new_config, NULL) PHP_FE(pspell_check, NULL) PHP_FE(pspell_suggest, NULL) PHP_FE(pspell_store_replacement, NULL) PHP_FE(pspell_add_to_personal, NULL) PHP_FE(pspell_add_to_session, NULL) PHP_FE(pspell_clear_session, NULL) PHP_FE(pspell_save_wordlist, NULL) PHP_FE(pspell_config_create, NULL) PHP_FE(pspell_config_runtogether, NULL) PHP_FE(pspell_config_mode, NULL) PHP_FE(pspell_config_ignore, NULL) PHP_FE(pspell_config_personal, NULL) PHP_FE(pspell_config_repl, NULL) PHP_FE(pspell_config_save_repl, NULL) }; static int le_pspell, le_pspell_config; zend_module_entry pspell_module_entry = { "pspell", pspell_functions, PHP_MINIT(pspell), NULL, NULL, NULL, PHP_MINFO(pspell), STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_PSPELL ZEND_GET_MODULE(pspell) #endif static void php_pspell_close(PspellManager *manager){ delete_pspell_manager(manager); } static void php_pspell_close_config(PspellConfig *config){ delete_pspell_config(config); } PHP_MINIT_FUNCTION(pspell){ REGISTER_MAIN_LONG_CONSTANT("PSPELL_FAST", PSPELL_FAST, CONST_PERSISTENT | CONST_CS); REGISTER_MAIN_LONG_CONSTANT("PSPELL_NORMAL", PSPELL_NORMAL, CONST_PERSISTENT | CONST_CS); REGISTER_MAIN_LONG_CONSTANT("PSPELL_BAD_SPELLERS", PSPELL_BAD_SPELLERS, CONST_PERSISTENT | CONST_CS); REGISTER_MAIN_LONG_CONSTANT("PSPELL_RUN_TOGETHER", PSPELL_RUN_TOGETHER, CONST_PERSISTENT | CONST_CS); le_pspell = register_list_destructors(php_pspell_close,NULL); le_pspell_config = register_list_destructors(php_pspell_close_config,NULL); return SUCCESS; } /* {{{ proto int pspell_new(string language [, string spelling [, string jargon [, string encoding [, int mode]]]]) Load a dictionary */ PHP_FUNCTION(pspell_new){ zval **language,**spelling,**jargon,**encoding,**pmode; long mode = 0L, speed = 0L; int argc; int ind; PspellCanHaveError *ret; PspellManager *manager; PspellConfig *config; argc = ZEND_NUM_ARGS(); if (argc < 1 || argc > 5 || zend_get_parameters_ex(argc,&language,&spelling,&jargon,&encoding,&pmode) == FAILURE) { WRONG_PARAM_COUNT; } config = new_pspell_config(); convert_to_string_ex(language); pspell_config_replace(config, "language-tag", (*language)->value.str.val); if(argc > 1){ convert_to_string_ex(spelling); if((*spelling)->value.str.len > 0){ pspell_config_replace(config, "spelling", (*spelling)->value.str.val); } } if(argc > 2){ convert_to_string_ex(jargon); if((*jargon)->value.str.len > 0){ pspell_config_replace(config, "jargon", (*jargon)->value.str.val); } } if(argc > 3){ convert_to_string_ex(encoding); if((*encoding)->value.str.len > 0){ pspell_config_replace(config, "encoding", (*encoding)->value.str.val); } } if(argc > 4){ convert_to_long_ex(pmode); mode = Z_LVAL_PP(pmode); speed = mode & PSPELL_SPEED_MASK_INTERNAL; /* First check what mode we want (how many suggestions) */ if(speed == PSPELL_FAST){ pspell_config_replace(config, "sug-mode", "fast"); }else if(speed == PSPELL_NORMAL){ pspell_config_replace(config, "sug-mode", "normal"); }else if(speed == PSPELL_BAD_SPELLERS){ pspell_config_replace(config, "sug-mode", "bad-spellers"); } /* Then we see if run-together words should be treated as valid components */ if(mode & PSPELL_RUN_TOGETHER){ pspell_config_replace(config, "run-together", "true"); } } ret = new_pspell_manager(config); delete_pspell_config(config); if(pspell_error_number(ret) != 0){ php_error(E_WARNING, "PSPELL couldn't open the dictionary. reason: %s ", pspell_error_message(ret)); RETURN_FALSE; } manager = to_pspell_manager(ret); ind = zend_list_insert(manager, le_pspell); RETURN_LONG(ind); } /* }}} */ /* {{{ proto int pspell_new_personal(string personal, string language [, string spelling [, string jargon [, string encoding [, int mode]]]]) Load a dictionary with a personal wordlist*/ PHP_FUNCTION(pspell_new_personal){ zval **personal, **language,**spelling,**jargon,**encoding,**pmode; long mode = 0L, speed = 0L; int argc; int ind; PspellCanHaveError *ret; PspellManager *manager; PspellConfig *config; argc = ZEND_NUM_ARGS(); if (argc < 2 || argc > 6 || zend_get_parameters_ex(argc,&personal,&language,&spelling,&jargon,&encoding,&pmode) == FAILURE) { WRONG_PARAM_COUNT; } config = new_pspell_config(); convert_to_string_ex(personal); pspell_config_replace(config, "personal", (*personal)->value.str.val); pspell_config_replace(config, "save-repl", "false"); convert_to_string_ex(language); pspell_config_replace(config, "language-tag", (*language)->value.str.val); if(argc > 2){ convert_to_string_ex(spelling); if((*spelling)->value.str.len > 0){ pspell_config_replace(config, "spelling", (*spelling)->value.str.val); } } if(argc > 3){ convert_to_string_ex(jargon); if((*jargon)->value.str.len > 0){ pspell_config_replace(config, "jargon", (*jargon)->value.str.val); } } if(argc > 4){ convert_to_string_ex(encoding); if((*encoding)->value.str.len > 0){ pspell_config_replace(config, "encoding", (*encoding)->value.str.val); } } if(argc > 5){ convert_to_long_ex(pmode); mode = Z_LVAL_PP(pmode); speed = mode & PSPELL_SPEED_MASK_INTERNAL; /* First check what mode we want (how many suggestions) */ if(speed == PSPELL_FAST){ pspell_config_replace(config, "sug-mode", "fast"); }else if(speed == PSPELL_NORMAL){ pspell_config_replace(config, "sug-mode", "normal"); }else if(speed == PSPELL_BAD_SPELLERS){ pspell_config_replace(config, "sug-mode", "bad-spellers"); } /* Then we see if run-together words should be treated as valid components */ if(mode & PSPELL_RUN_TOGETHER){ pspell_config_replace(config, "run-together", "true"); } } ret = new_pspell_manager(config); delete_pspell_config(config); if(pspell_error_number(ret) != 0){ php_error(E_WARNING, "PSPELL couldn't open the dictionary. reason: %s ", pspell_error_message(ret)); RETURN_FALSE; } manager = to_pspell_manager(ret); ind = zend_list_insert(manager, le_pspell); RETURN_LONG(ind); } /* }}} */ /* {{{ proto int pspell_new_config(int config) Load a dictionary based on the given config */ PHP_FUNCTION(pspell_new_config){ int type; zval **conf; int argc; int ind; PspellCanHaveError *ret; PspellManager *manager; PspellConfig *config; argc = ZEND_NUM_ARGS(); if (argc != 1 || zend_get_parameters_ex(argc,&conf) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long_ex(conf); config = (PspellConfig *) zend_list_find((*conf)->value.lval, &type); ret = new_pspell_manager(config); if(pspell_error_number(ret) != 0){ php_error(E_WARNING, "PSPELL couldn't open the dictionary. reason: %s ", pspell_error_message(ret)); RETURN_FALSE; } manager = to_pspell_manager(ret); ind = zend_list_insert(manager, le_pspell); RETURN_LONG(ind); } /* }}} */ /* {{{ proto int pspell_check(int pspell, string word) Returns true if word is valid */ PHP_FUNCTION(pspell_check){ int type; zval **scin,**word; PspellManager *manager; int argc; argc = ZEND_NUM_ARGS(); if (argc != 2 || zend_get_parameters_ex(argc, &scin,&word) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long_ex(scin); convert_to_string_ex(word); manager = (PspellManager *) zend_list_find((*scin)->value.lval, &type); if(!manager){ php_error(E_WARNING, "%d is not an PSPELL result index",(*scin)->value.lval); RETURN_FALSE; } if(pspell_manager_check(manager, (*word)->value.str.val)){ RETURN_TRUE; }else{ RETURN_FALSE; } } /* }}} */ /* {{{ proto array pspell_suggest(int pspell, string word) Returns array of suggestions */ PHP_FUNCTION(pspell_suggest) { zval **scin, **word; int argc; PspellManager *manager; int type; const PspellWordList *wl; const char *sug; argc = ZEND_NUM_ARGS(); if(argc != 2 || zend_get_parameters_ex(argc, &scin,&word) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long_ex(scin); convert_to_string_ex(word); manager = (PspellManager *) zend_list_find((*scin)->value.lval, &type); if(!manager){ php_error(E_WARNING, "%d is not an PSPELL result index",(*scin)->value.lval); RETURN_FALSE; } if (array_init(return_value) == FAILURE){ RETURN_FALSE; } wl = pspell_manager_suggest(manager, (*word)->value.str.val); if(wl){ PspellStringEmulation *els = pspell_word_list_elements(wl); while((sug = pspell_string_emulation_next(els)) != 0){ add_next_index_string(return_value,(char *)sug,1); } delete_pspell_string_emulation(els); }else{ php_error(E_WARNING, "PSPELL had a problem. details: %s ", pspell_manager_error_message(manager)); RETURN_FALSE; } } /* }}} */ /* {{{ proto int pspell_store_replacement(int pspell, string misspell, string correct) Notify the dictionary of a user-selected replacement */ PHP_FUNCTION(pspell_store_replacement) { int type; zval **scin,**miss,**corr; PspellManager *manager; int argc; argc = ZEND_NUM_ARGS(); if (argc != 3 || zend_get_parameters_ex(argc, &scin,&miss,&corr) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long_ex(scin); convert_to_string_ex(miss); convert_to_string_ex(corr); manager = (PspellManager *) zend_list_find((*scin)->value.lval, &type); if(!manager){ php_error(E_WARNING, "%d is not an PSPELL result index",(*scin)->value.lval); RETURN_FALSE; } pspell_manager_store_replacement(manager, (*miss)->value.str.val, (*corr)->value.str.val); if(pspell_manager_error_number(manager) == 0){ RETURN_TRUE; }else{ php_error(E_WARNING, "pspell_store_replacement() gave error: %s", pspell_manager_error_message(manager)); RETURN_FALSE; } } /* }}} */ /* {{{ proto int pspell_add_to_personal(int pspell, string word) Adds a word to a personal list */ PHP_FUNCTION(pspell_add_to_personal) { int type; zval **scin,**word; PspellManager *manager; int argc; argc = ZEND_NUM_ARGS(); if (argc != 2 || zend_get_parameters_ex(argc, &scin,&word) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long_ex(scin); convert_to_string_ex(word); manager = (PspellManager *) zend_list_find((*scin)->value.lval, &type); if(!manager){ php_error(E_WARNING, "%d is not an PSPELL result index",(*scin)->value.lval); RETURN_FALSE; } /*If the word is empty, we have to return; otherwise we'll segfault! ouch!*/ if((*word)->value.str.len == 0){ RETURN_FALSE; } pspell_manager_add_to_personal(manager, (*word)->value.str.val); if(pspell_manager_error_number(manager) == 0){ RETURN_TRUE; }else{ php_error(E_WARNING, "pspell_add_to_personal() gave error: %s", pspell_manager_error_message(manager)); RETURN_FALSE; } } /* }}} */ /* {{{ proto int pspell_add_to_session(int pspell, string word) Adds a word to the current session */ PHP_FUNCTION(pspell_add_to_session) { int type; zval **scin,**word; PspellManager *manager; int argc; argc = ZEND_NUM_ARGS(); if (argc != 2 || zend_get_parameters_ex(argc, &scin,&word) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long_ex(scin); convert_to_string_ex(word); manager = (PspellManager *) zend_list_find((*scin)->value.lval, &type); if(!manager){ php_error(E_WARNING, "%d is not an PSPELL result index",(*scin)->value.lval); RETURN_FALSE; } /*If the word is empty, we have to return; otherwise we'll segfault! ouch!*/ if((*word)->value.str.len == 0){ RETURN_FALSE; } pspell_manager_add_to_session(manager, (*word)->value.str.val); if(pspell_manager_error_number(manager) == 0){ RETURN_TRUE; }else{ php_error(E_WARNING, "pspell_add_to_session() gave error: %s", pspell_manager_error_message(manager)); RETURN_FALSE; } } /* }}} */ /* {{{ proto int pspell_clear_session(int pspell) Clears the current session */ PHP_FUNCTION(pspell_clear_session) { int type; zval **scin; PspellManager *manager; int argc; argc = ZEND_NUM_ARGS(); if (argc != 1 || zend_get_parameters_ex(argc, &scin) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long_ex(scin); manager = (PspellManager *) zend_list_find((*scin)->value.lval, &type); if(!manager){ php_error(E_WARNING, "%d is not an PSPELL result index",(*scin)->value.lval); RETURN_FALSE; } pspell_manager_clear_session(manager); if(pspell_manager_error_number(manager) == 0){ RETURN_TRUE; }else{ php_error(E_WARNING, "pspell_clear_session() gave error: %s", pspell_manager_error_message(manager)); RETURN_FALSE; } } /* }}} */ /* {{{ proto int pspell_save_wordlist(int pspell) Saves the current (personal) wordlist */ PHP_FUNCTION(pspell_save_wordlist) { int type; zval **scin; PspellManager *manager; int argc; argc = ZEND_NUM_ARGS(); if (argc != 1 || zend_get_parameters_ex(argc, &scin) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long_ex(scin); manager = (PspellManager *) zend_list_find((*scin)->value.lval, &type); if(!manager){ php_error(E_WARNING, "%d is not an PSPELL result index",(*scin)->value.lval); RETURN_FALSE; } pspell_manager_save_all_word_lists(manager); if(pspell_manager_error_number(manager) == 0){ RETURN_TRUE; }else{ php_error(E_WARNING, "pspell_save_wordlist() gave error: %s", pspell_manager_error_message(manager)); RETURN_FALSE; } } /* }}} */ /* {{{ proto int pspell_config_create(string language [, string spelling [, string jargon [, string encoding]]]) Create a new config to be used later to create a manager */ PHP_FUNCTION(pspell_config_create){ zval **language,**spelling,**jargon,**encoding; int argc; int ind; PspellConfig *config; argc = ZEND_NUM_ARGS(); if (argc < 1 || argc > 4 || zend_get_parameters_ex(argc,&language,&spelling,&jargon,&encoding) == FAILURE) { WRONG_PARAM_COUNT; } config = new_pspell_config(); convert_to_string_ex(language); pspell_config_replace(config, "language-tag", (*language)->value.str.val); if(argc > 1){ convert_to_string_ex(spelling); if((*spelling)->value.str.len > 0){ pspell_config_replace(config, "spelling", (*spelling)->value.str.val); } } if(argc > 2){ convert_to_string_ex(jargon); if((*jargon)->value.str.len > 0){ pspell_config_replace(config, "jargon", (*jargon)->value.str.val); } } if(argc > 3){ convert_to_string_ex(encoding); if((*encoding)->value.str.len > 0){ pspell_config_replace(config, "encoding", (*encoding)->value.str.val); } } /* By default I do not want to write anything anywhere because it'll try to write to $HOME which is not what we want */ pspell_config_replace(config, "save-repl", "false"); ind = zend_list_insert(config, le_pspell_config); RETURN_LONG(ind); } /* }}} */ /* {{{ proto int pspell_config_runtogether(int conf, bool runtogether) Consider run-together words as valid components */ PHP_FUNCTION(pspell_config_runtogether){ int type; zval **sccin, **runtogether; int argc; PspellConfig *config; argc = ZEND_NUM_ARGS(); if (argc != 2 || zend_get_parameters_ex(argc,&sccin,&runtogether) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long_ex(sccin); config = (PspellConfig *) zend_list_find((*sccin)->value.lval, &type); if(!config){ php_error(E_WARNING, "%d is not an PSPELL config index",(*sccin)->value.lval); RETURN_FALSE; } convert_to_boolean_ex(runtogether); pspell_config_replace(config, "run-together", (*runtogether)->value.lval ? "true" : "false"); RETURN_TRUE; } /* }}} */ /* {{{ proto int pspell_config_mode(int conf, long mode) Select mode for config (PSPELL_FAST, PSPELL_NORMAL or PSPELL_BAD_SPELLERS) */ PHP_FUNCTION(pspell_config_mode){ int type; zval **sccin, **mode; int argc; PspellConfig *config; argc = ZEND_NUM_ARGS(); if (argc != 2 || zend_get_parameters_ex(argc,&sccin,&mode) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long_ex(sccin); config = (PspellConfig *) zend_list_find((*sccin)->value.lval, &type); if(!config){ php_error(E_WARNING, "%d is not an PSPELL config index",(*sccin)->value.lval); RETURN_FALSE; } convert_to_long_ex(mode); /* First check what mode we want (how many suggestions) */ if((*mode)->value.lval == PSPELL_FAST){ pspell_config_replace(config, "sug-mode", "fast"); }else if((*mode)->value.lval == PSPELL_NORMAL){ pspell_config_replace(config, "sug-mode", "normal"); }else if((*mode)->value.lval == PSPELL_BAD_SPELLERS){ pspell_config_replace(config, "sug-mode", "bad-spellers"); } RETURN_TRUE; } /* }}} */ /* {{{ proto int pspell_config_ignore(int conf, int ignore) Ignore words <= n chars */ PHP_FUNCTION(pspell_config_ignore){ int type; zval **sccin, **pignore; int argc; /* Hack. But I cannot imagine any word being more than 999 characters long */ int loc = 3; char ignore_str[loc + 1]; long ignore = 0L; PspellConfig *config; argc = ZEND_NUM_ARGS(); if (argc != 2 || zend_get_parameters_ex(argc,&sccin,&pignore) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long_ex(sccin); config = (PspellConfig *) zend_list_find((*sccin)->value.lval, &type); if(!config){ php_error(E_WARNING, "%d is not an PSPELL config index",(*sccin)->value.lval); RETURN_FALSE; } convert_to_long_ex(pignore); ignore = Z_LVAL_PP(pignore); /* The following is a very hackish way to convert a long to a string (actually only the numbers 0-999 will get converted properly, but that should be sufficient). If anyone knows of a better way to convert an integer to a string, please, fix it.*/ ignore_str[loc] = '\0'; while(ignore > 0){ if(loc == 0){ break; } ignore_str[--loc] = '0' + (ignore % 10); ignore /= 10; } if(ignore_str[loc] == '\0'){ ignore_str[--loc] = '0'; } pspell_config_replace(config, "ignore", &ignore_str[loc]); RETURN_TRUE; } /* }}} */ /* {{{ proto int pspell_config_personal(int conf, string personal) Use a personal dictionary for this config */ PHP_FUNCTION(pspell_config_personal){ int type; zval **sccin, **personal; int argc; PspellConfig *config; argc = ZEND_NUM_ARGS(); if (argc != 2 || zend_get_parameters_ex(argc,&sccin,&personal) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long_ex(sccin); config = (PspellConfig *) zend_list_find((*sccin)->value.lval, &type); if(!config){ php_error(E_WARNING, "%d is not an PSPELL config index",(*sccin)->value.lval); RETURN_FALSE; } convert_to_string_ex(personal); pspell_config_replace(config, "personal", (*personal)->value.str.val); RETURN_TRUE; } /* }}} */ /* {{{ proto int pspell_config_repl(int conf, string repl) Use a personal dictionary with replacement pairs for this config */ PHP_FUNCTION(pspell_config_repl){ int type; zval **sccin, **repl; int argc; PspellConfig *config; argc = ZEND_NUM_ARGS(); if (argc != 2 || zend_get_parameters_ex(argc,&sccin,&repl) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long_ex(sccin); config = (PspellConfig *) zend_list_find((*sccin)->value.lval, &type); if(!config){ php_error(E_WARNING, "%d is not an PSPELL config index",(*sccin)->value.lval); RETURN_FALSE; } pspell_config_replace(config, "save-repl", "true"); convert_to_string_ex(repl); pspell_config_replace(config, "repl", (*repl)->value.str.val); RETURN_TRUE; } /* }}} */ /* {{{ proto int pspell_config_save_repl(int conf, bool save) Save replacement pairs when personal list is saved for this config */ PHP_FUNCTION(pspell_config_save_repl){ int type; zval **sccin, **save; int argc; PspellConfig *config; argc = ZEND_NUM_ARGS(); if (argc != 2 || zend_get_parameters_ex(argc,&sccin,&save) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long_ex(sccin); config = (PspellConfig *) zend_list_find((*sccin)->value.lval, &type); if(!config){ php_error(E_WARNING, "%d is not an PSPELL config index",(*sccin)->value.lval); RETURN_FALSE; } convert_to_boolean_ex(save); pspell_config_replace(config, "save-repl", (*save)->value.lval ? "true" : "false"); RETURN_TRUE; } /* }}} */ PHP_MINFO_FUNCTION(pspell) { php_info_print_table_start(); php_info_print_table_row(2, "PSpell Support", "enabled"); php_info_print_table_end(); } #endif