Back to index

php5  5.3.10
pspell.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Vlad Krupin <phpdevel@echospace.com>                         |
00016    +----------------------------------------------------------------------+
00017 */
00018 
00019 /* $Id: pspell.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #define IS_EXT_MODULE
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif
00026 
00027 #include "php.h"
00028 
00029 #include <stdlib.h>
00030 #include <ctype.h>
00031 #include <stdio.h>
00032 
00033 #if HAVE_PSPELL
00034 
00035 /* this will enforce compatibility in .12 version (broken after .11.2) */
00036 #define USE_ORIGINAL_MANAGER_FUNCS
00037 
00038 #include "php_pspell.h"
00039 #include <pspell.h>
00040 #include "ext/standard/info.h"
00041 
00042 #define PSPELL_FAST 1L
00043 #define PSPELL_NORMAL 2L
00044 #define PSPELL_BAD_SPELLERS 3L
00045 #define PSPELL_SPEED_MASK_INTERNAL 3L
00046 #define PSPELL_RUN_TOGETHER 8L
00047 
00048 /* Largest ignored word can be 999 characters (this seems sane enough), 
00049  * and it takes 3 bytes to represent that (see pspell_config_ignore)
00050  */
00051 #define PSPELL_LARGEST_WORD 3
00052 
00053 static PHP_MINIT_FUNCTION(pspell);
00054 static PHP_MINFO_FUNCTION(pspell);
00055 static PHP_FUNCTION(pspell_new);
00056 static PHP_FUNCTION(pspell_new_personal);
00057 static PHP_FUNCTION(pspell_new_config);
00058 static PHP_FUNCTION(pspell_check);
00059 static PHP_FUNCTION(pspell_suggest);
00060 static PHP_FUNCTION(pspell_store_replacement);
00061 static PHP_FUNCTION(pspell_add_to_personal);
00062 static PHP_FUNCTION(pspell_add_to_session);
00063 static PHP_FUNCTION(pspell_clear_session);
00064 static PHP_FUNCTION(pspell_save_wordlist);
00065 static PHP_FUNCTION(pspell_config_create);
00066 static PHP_FUNCTION(pspell_config_runtogether);
00067 static PHP_FUNCTION(pspell_config_mode);
00068 static PHP_FUNCTION(pspell_config_ignore);
00069 static PHP_FUNCTION(pspell_config_personal);
00070 static PHP_FUNCTION(pspell_config_dict_dir);
00071 static PHP_FUNCTION(pspell_config_data_dir);
00072 static PHP_FUNCTION(pspell_config_repl);
00073 static PHP_FUNCTION(pspell_config_save_repl);
00074 
00075 /* {{{ arginfo */
00076 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_new, 0, 0, 1)
00077        ZEND_ARG_INFO(0, language)
00078        ZEND_ARG_INFO(0, spelling)
00079        ZEND_ARG_INFO(0, jargon)
00080        ZEND_ARG_INFO(0, encoding)
00081        ZEND_ARG_INFO(0, mode)
00082 ZEND_END_ARG_INFO()
00083 
00084 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_new_personal, 0, 0, 2)
00085        ZEND_ARG_INFO(0, personal)
00086        ZEND_ARG_INFO(0, language)
00087        ZEND_ARG_INFO(0, spelling)
00088        ZEND_ARG_INFO(0, jargon)
00089        ZEND_ARG_INFO(0, encoding)
00090        ZEND_ARG_INFO(0, mode)
00091 ZEND_END_ARG_INFO()
00092 
00093 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_new_config, 0, 0, 1)
00094        ZEND_ARG_INFO(0, config)
00095 ZEND_END_ARG_INFO()
00096 
00097 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_check, 0, 0, 2)
00098        ZEND_ARG_INFO(0, pspell)
00099        ZEND_ARG_INFO(0, word)
00100 ZEND_END_ARG_INFO()
00101 
00102 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_suggest, 0, 0, 2)
00103        ZEND_ARG_INFO(0, pspell)
00104        ZEND_ARG_INFO(0, word)
00105 ZEND_END_ARG_INFO()
00106 
00107 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_store_replacement, 0, 0, 3)
00108        ZEND_ARG_INFO(0, pspell)
00109        ZEND_ARG_INFO(0, misspell)
00110        ZEND_ARG_INFO(0, correct)
00111 ZEND_END_ARG_INFO()
00112 
00113 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_add_to_personal, 0, 0, 2)
00114        ZEND_ARG_INFO(0, pspell)
00115        ZEND_ARG_INFO(0, word)
00116 ZEND_END_ARG_INFO()
00117 
00118 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_add_to_session, 0, 0, 2)
00119        ZEND_ARG_INFO(0, pspell)
00120        ZEND_ARG_INFO(0, word)
00121 ZEND_END_ARG_INFO()
00122 
00123 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_clear_session, 0, 0, 1)
00124        ZEND_ARG_INFO(0, pspell)
00125 ZEND_END_ARG_INFO()
00126 
00127 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_save_wordlist, 0, 0, 1)
00128        ZEND_ARG_INFO(0, pspell)
00129 ZEND_END_ARG_INFO()
00130 
00131 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_create, 0, 0, 1)
00132        ZEND_ARG_INFO(0, language)
00133        ZEND_ARG_INFO(0, spelling)
00134        ZEND_ARG_INFO(0, jargon)
00135        ZEND_ARG_INFO(0, encoding)
00136 ZEND_END_ARG_INFO()
00137 
00138 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_runtogether, 0, 0, 2)
00139        ZEND_ARG_INFO(0, conf)
00140        ZEND_ARG_INFO(0, runtogether)
00141 ZEND_END_ARG_INFO()
00142 
00143 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_mode, 0, 0, 2)
00144        ZEND_ARG_INFO(0, conf)
00145        ZEND_ARG_INFO(0, mode)
00146 ZEND_END_ARG_INFO()
00147 
00148 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_ignore, 0, 0, 2)
00149        ZEND_ARG_INFO(0, conf)
00150        ZEND_ARG_INFO(0, ignore)
00151 ZEND_END_ARG_INFO()
00152 
00153 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_personal, 0, 0, 2)
00154        ZEND_ARG_INFO(0, conf)
00155        ZEND_ARG_INFO(0, personal)
00156 ZEND_END_ARG_INFO()
00157 
00158 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_dict_dir, 0, 0, 2)
00159        ZEND_ARG_INFO(0, conf)
00160        ZEND_ARG_INFO(0, directory)
00161 ZEND_END_ARG_INFO()
00162 
00163 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_data_dir, 0, 0, 2)
00164        ZEND_ARG_INFO(0, conf)
00165        ZEND_ARG_INFO(0, directory)
00166 ZEND_END_ARG_INFO()
00167 
00168 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_repl, 0, 0, 2)
00169        ZEND_ARG_INFO(0, conf)
00170        ZEND_ARG_INFO(0, repl)
00171 ZEND_END_ARG_INFO()
00172 
00173 ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_save_repl, 0, 0, 2)
00174        ZEND_ARG_INFO(0, conf)
00175        ZEND_ARG_INFO(0, save)
00176 ZEND_END_ARG_INFO()
00177 /* }}} */
00178 
00179 /* {{{ pspell_functions[]
00180  */
00181 static const zend_function_entry pspell_functions[] = {
00182        PHP_FE(pspell_new,                               arginfo_pspell_new)
00183        PHP_FE(pspell_new_personal,               arginfo_pspell_new_personal)
00184        PHP_FE(pspell_new_config,                 arginfo_pspell_new_config)
00185        PHP_FE(pspell_check,                      arginfo_pspell_check)
00186        PHP_FE(pspell_suggest,                           arginfo_pspell_suggest)
00187        PHP_FE(pspell_store_replacement,   arginfo_pspell_store_replacement)
00188        PHP_FE(pspell_add_to_personal,            arginfo_pspell_add_to_personal)
00189        PHP_FE(pspell_add_to_session,             arginfo_pspell_add_to_session)
00190        PHP_FE(pspell_clear_session,              arginfo_pspell_clear_session)
00191        PHP_FE(pspell_save_wordlist,              arginfo_pspell_save_wordlist)
00192        PHP_FE(pspell_config_create,              arginfo_pspell_config_create)
00193        PHP_FE(pspell_config_runtogether,  arginfo_pspell_config_runtogether)
00194        PHP_FE(pspell_config_mode,                arginfo_pspell_config_mode)
00195        PHP_FE(pspell_config_ignore,              arginfo_pspell_config_ignore)
00196        PHP_FE(pspell_config_personal,            arginfo_pspell_config_personal)
00197        PHP_FE(pspell_config_dict_dir,            arginfo_pspell_config_dict_dir)
00198        PHP_FE(pspell_config_data_dir,            arginfo_pspell_config_data_dir)
00199        PHP_FE(pspell_config_repl,                arginfo_pspell_config_repl)
00200        PHP_FE(pspell_config_save_repl,           arginfo_pspell_config_save_repl)
00201        PHP_FE_END
00202 };
00203 /* }}} */
00204 
00205 static int le_pspell, le_pspell_config;
00206 
00207 zend_module_entry pspell_module_entry = {
00208     STANDARD_MODULE_HEADER,
00209        "pspell", pspell_functions, PHP_MINIT(pspell), NULL, NULL, NULL, PHP_MINFO(pspell), NO_VERSION_YET, STANDARD_MODULE_PROPERTIES
00210 };
00211 
00212 #ifdef COMPILE_DL_PSPELL
00213 ZEND_GET_MODULE(pspell)
00214 #endif
00215 
00216 static void php_pspell_close(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00217 {
00218        PspellManager *manager = (PspellManager *)rsrc->ptr;
00219 
00220        delete_pspell_manager(manager);
00221 }
00222 
00223 static void php_pspell_close_config(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00224 {
00225        PspellConfig *config = (PspellConfig *)rsrc->ptr;
00226 
00227        delete_pspell_config(config);
00228 }
00229 
00230 #define PSPELL_FETCH_CONFIG \
00231        config = (PspellConfig *) zend_list_find(conf, &type);  \
00232        if (config == NULL || type != le_pspell_config) {       \
00233               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%ld is not a PSPELL config index", conf);     \
00234               RETURN_FALSE; \
00235        }      \
00236 
00237 #define PSPELL_FETCH_MANAGER \
00238        manager = (PspellManager *) zend_list_find(scin, &type);       \
00239        if (!manager || type != le_pspell) {      \
00240               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%ld is not a PSPELL result index", scin);     \
00241               RETURN_FALSE; \
00242        }      \
00243 
00244 /* {{{ PHP_MINIT_FUNCTION
00245  */
00246 static PHP_MINIT_FUNCTION(pspell)
00247 {
00248        REGISTER_LONG_CONSTANT("PSPELL_FAST", PSPELL_FAST, CONST_PERSISTENT | CONST_CS);
00249        REGISTER_LONG_CONSTANT("PSPELL_NORMAL", PSPELL_NORMAL, CONST_PERSISTENT | CONST_CS);
00250        REGISTER_LONG_CONSTANT("PSPELL_BAD_SPELLERS", PSPELL_BAD_SPELLERS, CONST_PERSISTENT | CONST_CS);
00251        REGISTER_LONG_CONSTANT("PSPELL_RUN_TOGETHER", PSPELL_RUN_TOGETHER, CONST_PERSISTENT | CONST_CS);
00252        le_pspell = zend_register_list_destructors_ex(php_pspell_close, NULL, "pspell", module_number);
00253        le_pspell_config = zend_register_list_destructors_ex(php_pspell_close_config, NULL, "pspell config", module_number);
00254        return SUCCESS;
00255 }
00256 /* }}} */
00257 
00258 /* {{{ proto int pspell_new(string language [, string spelling [, string jargon [, string encoding [, int mode]]]])
00259    Load a dictionary */
00260 static PHP_FUNCTION(pspell_new)
00261 {
00262        char *language, *spelling = NULL, *jargon = NULL, *encoding = NULL;
00263        int language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0;
00264        long mode = 0L,  speed = 0L;
00265        int argc = ZEND_NUM_ARGS();
00266        int ind;
00267 
00268 #ifdef PHP_WIN32
00269        TCHAR aspell_dir[200];
00270        TCHAR data_dir[220];
00271        TCHAR dict_dir[220];
00272        HKEY hkey;
00273        DWORD dwType,dwLen;
00274 #endif
00275 
00276        PspellCanHaveError *ret;
00277        PspellManager *manager;
00278        PspellConfig *config;
00279        
00280        if (zend_parse_parameters(argc TSRMLS_CC, "s|sssl", &language, &language_len, &spelling, &spelling_len,
00281               &jargon, &jargon_len, &encoding, &encoding_len, &mode) == FAILURE) {
00282               return;
00283        }
00284 
00285        config = new_pspell_config();
00286 
00287 #ifdef PHP_WIN32
00288        /* If aspell was installed using installer, we should have a key
00289         * pointing to the location of the dictionaries
00290         */
00291        if (0 == RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Aspell", &hkey)) {
00292               LONG result;
00293               dwLen = sizeof(aspell_dir) - 1;
00294               result = RegQueryValueEx(hkey, "", NULL, &dwType, (LPBYTE)&aspell_dir, &dwLen);
00295               RegCloseKey(hkey);
00296               if (result == ERROR_SUCCESS) {
00297                      strlcpy(data_dir, aspell_dir, sizeof(data_dir));
00298                      strlcat(data_dir, "\\data", sizeof(data_dir));
00299                      strlcpy(dict_dir, aspell_dir, sizeof(dict_dir));
00300                      strlcat(dict_dir, "\\dict", sizeof(dict_dir));
00301 
00302                      pspell_config_replace(config, "data-dir", data_dir);
00303                      pspell_config_replace(config, "dict-dir", dict_dir);
00304               }
00305        }
00306 #endif
00307 
00308        pspell_config_replace(config, "language-tag", language);
00309 
00310        if (spelling_len) {
00311               pspell_config_replace(config, "spelling", spelling);
00312        }
00313 
00314        if (jargon_len) {
00315               pspell_config_replace(config, "jargon", jargon);
00316        }
00317 
00318        if (encoding_len) {
00319               pspell_config_replace(config, "encoding", encoding);
00320        }
00321 
00322        if (argc > 4) {
00323               speed = mode & PSPELL_SPEED_MASK_INTERNAL;
00324 
00325               /* First check what mode we want (how many suggestions) */
00326               if (speed == PSPELL_FAST) {
00327                      pspell_config_replace(config, "sug-mode", "fast");
00328               } else if (speed == PSPELL_NORMAL) {
00329                      pspell_config_replace(config, "sug-mode", "normal");
00330               } else if (speed == PSPELL_BAD_SPELLERS) {
00331                      pspell_config_replace(config, "sug-mode", "bad-spellers");
00332               }
00333               
00334               /* Then we see if run-together words should be treated as valid components */
00335               if (mode & PSPELL_RUN_TOGETHER) {
00336                      pspell_config_replace(config, "run-together", "true");
00337               }
00338        }
00339 
00340        ret = new_pspell_manager(config);
00341        delete_pspell_config(config);
00342 
00343        if (pspell_error_number(ret) != 0) {
00344               php_error_docref(NULL TSRMLS_CC, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret));
00345               delete_pspell_can_have_error(ret);
00346               RETURN_FALSE;
00347        }
00348        
00349        manager = to_pspell_manager(ret);
00350        ind = zend_list_insert(manager, le_pspell);
00351        RETURN_LONG(ind);
00352 }
00353 /* }}} */
00354 
00355 /* {{{ proto int pspell_new_personal(string personal, string language [, string spelling [, string jargon [, string encoding [, int mode]]]])
00356    Load a dictionary with a personal wordlist*/
00357 static PHP_FUNCTION(pspell_new_personal)
00358 {
00359        char *personal, *language, *spelling = NULL, *jargon = NULL, *encoding = NULL;
00360        int personal_len, language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0;
00361        long mode = 0L,  speed = 0L;
00362        int argc = ZEND_NUM_ARGS();
00363        int ind;
00364 
00365 #ifdef PHP_WIN32
00366        TCHAR aspell_dir[200];
00367        TCHAR data_dir[220];
00368        TCHAR dict_dir[220];
00369        HKEY hkey;
00370        DWORD dwType,dwLen;
00371 #endif
00372 
00373        PspellCanHaveError *ret;
00374        PspellManager *manager;
00375        PspellConfig *config;
00376 
00377        if (zend_parse_parameters(argc TSRMLS_CC, "ss|sssl", &personal, &personal_len, &language, &language_len, 
00378               &spelling, &spelling_len, &jargon, &jargon_len, &encoding, &encoding_len, &mode) == FAILURE) {
00379               return;
00380        }
00381 
00382        config = new_pspell_config();
00383 
00384 #ifdef PHP_WIN32
00385        /* If aspell was installed using installer, we should have a key
00386         * pointing to the location of the dictionaries
00387         */
00388        if (0 == RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Aspell", &hkey)) {
00389               LONG result;
00390               dwLen = sizeof(aspell_dir) - 1;
00391               result = RegQueryValueEx(hkey, "", NULL, &dwType, (LPBYTE)&aspell_dir, &dwLen);
00392               RegCloseKey(hkey);
00393               if (result == ERROR_SUCCESS) {
00394                      strlcpy(data_dir, aspell_dir, sizeof(data_dir));
00395                      strlcat(data_dir, "\\data", sizeof(data_dir));
00396                      strlcpy(dict_dir, aspell_dir, sizeof(dict_dir));
00397                      strlcat(dict_dir, "\\dict", sizeof(dict_dir));
00398 
00399                      pspell_config_replace(config, "data-dir", data_dir);
00400                      pspell_config_replace(config, "dict-dir", dict_dir);
00401               }
00402        }
00403 #endif
00404 
00405        if (strlen(personal) != personal_len) {
00406               delete_pspell_config(config);
00407               RETURN_FALSE;
00408        }
00409 
00410        if (PG(safe_mode) && (!php_checkuid(personal, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
00411               delete_pspell_config(config);
00412               RETURN_FALSE;
00413        }
00414 
00415        if (php_check_open_basedir(personal TSRMLS_CC)) {
00416               delete_pspell_config(config);
00417               RETURN_FALSE;
00418        }
00419 
00420        pspell_config_replace(config, "personal", personal);
00421        pspell_config_replace(config, "save-repl", "false");
00422 
00423        pspell_config_replace(config, "language-tag", language);
00424 
00425        if (spelling_len) {
00426               pspell_config_replace(config, "spelling", spelling);
00427        }
00428 
00429        if (jargon_len) {
00430               pspell_config_replace(config, "jargon", jargon);
00431        }
00432 
00433        if (encoding_len) {
00434               pspell_config_replace(config, "encoding", encoding);
00435        }
00436 
00437        if (argc > 5) {
00438               speed = mode & PSPELL_SPEED_MASK_INTERNAL;
00439 
00440               /* First check what mode we want (how many suggestions) */
00441               if (speed == PSPELL_FAST) {
00442                      pspell_config_replace(config, "sug-mode", "fast");
00443               } else if (speed == PSPELL_NORMAL) {
00444                      pspell_config_replace(config, "sug-mode", "normal");
00445               } else if (speed == PSPELL_BAD_SPELLERS) {
00446                      pspell_config_replace(config, "sug-mode", "bad-spellers");
00447               }
00448               
00449               /* Then we see if run-together words should be treated as valid components */
00450               if (mode & PSPELL_RUN_TOGETHER) {
00451                      pspell_config_replace(config, "run-together", "true");
00452               }
00453        }
00454 
00455        ret = new_pspell_manager(config);
00456        delete_pspell_config(config);
00457 
00458        if (pspell_error_number(ret) != 0) {
00459               php_error_docref(NULL TSRMLS_CC, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret));
00460               delete_pspell_can_have_error(ret);
00461               RETURN_FALSE;
00462        }
00463        
00464        manager = to_pspell_manager(ret);
00465        ind = zend_list_insert(manager, le_pspell);
00466        RETURN_LONG(ind);
00467 }
00468 /* }}} */
00469 
00470 /* {{{ proto int pspell_new_config(int config)
00471    Load a dictionary based on the given config */
00472 static PHP_FUNCTION(pspell_new_config)
00473 {
00474        int type, ind;
00475        long conf;    
00476        PspellCanHaveError *ret;
00477        PspellManager *manager;
00478        PspellConfig *config;
00479        
00480        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &conf) == FAILURE) {
00481               return;
00482        }
00483 
00484        PSPELL_FETCH_CONFIG;
00485 
00486        ret = new_pspell_manager(config);
00487 
00488        if (pspell_error_number(ret) != 0) {
00489               php_error_docref(NULL TSRMLS_CC, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret));
00490               delete_pspell_can_have_error(ret);
00491               RETURN_FALSE;
00492        }
00493        
00494        manager = to_pspell_manager(ret);
00495        ind = zend_list_insert(manager, le_pspell);
00496        RETURN_LONG(ind);
00497 }
00498 /* }}} */
00499 
00500 /* {{{ proto bool pspell_check(int pspell, string word)
00501    Returns true if word is valid */
00502 static PHP_FUNCTION(pspell_check)
00503 {
00504        int type, word_len;
00505        long scin;
00506        char *word;
00507        PspellManager *manager;
00508 
00509        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &scin, &word, &word_len) == FAILURE) {
00510               return;
00511        }
00512 
00513        PSPELL_FETCH_MANAGER;
00514 
00515        if (pspell_manager_check(manager, word)) {
00516               RETURN_TRUE;
00517        } else {
00518               RETURN_FALSE;
00519        }
00520 }
00521 /* }}} */
00522 
00523 /* {{{ proto array pspell_suggest(int pspell, string word)
00524    Returns array of suggestions */
00525 static PHP_FUNCTION(pspell_suggest)
00526 {
00527        long scin;
00528        char *word;
00529        int word_len;
00530        PspellManager *manager;
00531        int type;
00532        const PspellWordList *wl;
00533        const char *sug;
00534 
00535        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &scin, &word, &word_len) == FAILURE) {
00536               return;
00537        }
00538 
00539        PSPELL_FETCH_MANAGER;
00540 
00541        array_init(return_value);
00542 
00543        wl = pspell_manager_suggest(manager, word);
00544        if (wl) {
00545               PspellStringEmulation *els = pspell_word_list_elements(wl);
00546               while ((sug = pspell_string_emulation_next(els)) != 0) {
00547                      add_next_index_string(return_value,(char *)sug,1);
00548               }
00549               delete_pspell_string_emulation(els);
00550        } else {
00551               php_error_docref(NULL TSRMLS_CC, E_WARNING, "PSPELL had a problem. details: %s", pspell_manager_error_message(manager));
00552               RETURN_FALSE;
00553        }
00554 }
00555 /* }}} */
00556 
00557 /* {{{ proto bool pspell_store_replacement(int pspell, string misspell, string correct)
00558    Notify the dictionary of a user-selected replacement */
00559 static PHP_FUNCTION(pspell_store_replacement)
00560 {
00561        int type, miss_len, corr_len;
00562        long scin;
00563        char *miss, *corr;
00564        PspellManager *manager;
00565 
00566        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lss", &scin, &miss, &miss_len, &corr, &corr_len) == FAILURE) {
00567               return;
00568        }
00569 
00570        PSPELL_FETCH_MANAGER;
00571 
00572        pspell_manager_store_replacement(manager, miss, corr);
00573        if (pspell_manager_error_number(manager) == 0) {
00574               RETURN_TRUE;
00575        } else {
00576               php_error_docref(NULL TSRMLS_CC, E_WARNING, "pspell_store_replacement() gave error: %s", pspell_manager_error_message(manager));
00577               RETURN_FALSE;
00578        }
00579 }
00580 /* }}} */
00581 
00582 /* {{{ proto bool pspell_add_to_personal(int pspell, string word)
00583    Adds a word to a personal list */
00584 static PHP_FUNCTION(pspell_add_to_personal)
00585 {
00586        int type, word_len;
00587        long scin;
00588        char *word;
00589        PspellManager *manager;
00590 
00591        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &scin, &word, &word_len) == FAILURE) {
00592               return;
00593        }
00594 
00595        PSPELL_FETCH_MANAGER;
00596 
00597        /*If the word is empty, we have to return; otherwise we'll segfault! ouch!*/
00598        if (word_len == 0) {
00599               RETURN_FALSE;
00600        }
00601        
00602        pspell_manager_add_to_personal(manager, word);
00603        if (pspell_manager_error_number(manager) == 0) {
00604               RETURN_TRUE;
00605        } else {
00606               php_error_docref(NULL TSRMLS_CC, E_WARNING, "pspell_add_to_personal() gave error: %s", pspell_manager_error_message(manager));
00607               RETURN_FALSE;
00608        }
00609 }
00610 /* }}} */
00611 
00612 /* {{{ proto bool pspell_add_to_session(int pspell, string word)
00613    Adds a word to the current session */
00614 static PHP_FUNCTION(pspell_add_to_session)
00615 {
00616        int type, word_len;
00617        long scin;
00618        char *word;
00619        PspellManager *manager;
00620 
00621        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &scin, &word, &word_len) == FAILURE) {
00622               return;
00623        }
00624 
00625        PSPELL_FETCH_MANAGER;
00626 
00627        /*If the word is empty, we have to return; otherwise we'll segfault! ouch!*/
00628        if (word_len == 0) {
00629               RETURN_FALSE;
00630        }
00631 
00632        pspell_manager_add_to_session(manager, word);
00633        if (pspell_manager_error_number(manager) == 0) {
00634               RETURN_TRUE;
00635        } else {
00636               php_error_docref(NULL TSRMLS_CC, E_WARNING, "pspell_add_to_session() gave error: %s", pspell_manager_error_message(manager));
00637               RETURN_FALSE;
00638        }
00639 }
00640 /* }}} */
00641 
00642 /* {{{ proto bool pspell_clear_session(int pspell)
00643    Clears the current session */
00644 static PHP_FUNCTION(pspell_clear_session)
00645 {
00646        int type;
00647        long scin;
00648        PspellManager *manager;
00649 
00650        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &scin) == FAILURE) {
00651               return;
00652        }
00653     
00654        PSPELL_FETCH_MANAGER;       
00655 
00656        pspell_manager_clear_session(manager);
00657        if (pspell_manager_error_number(manager) == 0) {
00658               RETURN_TRUE;
00659        } else {
00660               php_error_docref(NULL TSRMLS_CC, E_WARNING, "pspell_clear_session() gave error: %s", pspell_manager_error_message(manager));
00661               RETURN_FALSE;
00662        }
00663 }
00664 /* }}} */
00665 
00666 /* {{{ proto bool pspell_save_wordlist(int pspell)
00667    Saves the current (personal) wordlist */
00668 static PHP_FUNCTION(pspell_save_wordlist)
00669 {
00670        int type;
00671        long scin;
00672        PspellManager *manager;
00673 
00674        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &scin) == FAILURE) {
00675               return;
00676        }
00677     
00678        PSPELL_FETCH_MANAGER;       
00679 
00680        pspell_manager_save_all_word_lists(manager);
00681 
00682        if (pspell_manager_error_number(manager) == 0) {
00683               RETURN_TRUE;
00684        } else {
00685               php_error_docref(NULL TSRMLS_CC, E_WARNING, "pspell_save_wordlist() gave error: %s", pspell_manager_error_message(manager));
00686               RETURN_FALSE;
00687        }
00688 
00689 }
00690 /* }}} */
00691 
00692 /* {{{ proto int pspell_config_create(string language [, string spelling [, string jargon [, string encoding]]])
00693    Create a new config to be used later to create a manager */
00694 static PHP_FUNCTION(pspell_config_create)
00695 {
00696        char *language, *spelling = NULL, *jargon = NULL, *encoding = NULL;
00697        int language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0;
00698        int ind;
00699        PspellConfig *config;
00700 
00701 #ifdef PHP_WIN32
00702        TCHAR aspell_dir[200];
00703        TCHAR data_dir[220];
00704        TCHAR dict_dir[220];
00705        HKEY hkey;
00706        DWORD dwType,dwLen;
00707 #endif
00708        
00709        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sss", &language, &language_len, &spelling, &spelling_len, 
00710               &jargon, &jargon_len, &encoding, &encoding_len) == FAILURE) {
00711               return;
00712        }
00713 
00714        config = new_pspell_config();
00715 
00716 #ifdef PHP_WIN32
00717     /* If aspell was installed using installer, we should have a key
00718      * pointing to the location of the dictionaries
00719      */
00720        if (0 == RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Aspell", &hkey)) {
00721               LONG result;
00722               dwLen = sizeof(aspell_dir) - 1;
00723               result = RegQueryValueEx(hkey, "", NULL, &dwType, (LPBYTE)&aspell_dir, &dwLen);
00724               RegCloseKey(hkey);
00725               if (result == ERROR_SUCCESS) {
00726                      strlcpy(data_dir, aspell_dir, sizeof(data_dir));
00727                      strlcat(data_dir, "\\data", sizeof(data_dir));
00728                      strlcpy(dict_dir, aspell_dir, sizeof(dict_dir));
00729                      strlcat(dict_dir, "\\dict", sizeof(dict_dir));
00730 
00731                      pspell_config_replace(config, "data-dir", data_dir);
00732                      pspell_config_replace(config, "dict-dir", dict_dir);
00733               }
00734        }
00735 #endif
00736 
00737        pspell_config_replace(config, "language-tag", language);
00738 
00739        if (spelling_len) {
00740               pspell_config_replace(config, "spelling", spelling);
00741        }
00742 
00743        if (jargon_len) {
00744               pspell_config_replace(config, "jargon", jargon);
00745        }
00746 
00747        if (encoding_len) {
00748               pspell_config_replace(config, "encoding", encoding);
00749        }
00750 
00751        /* By default I do not want to write anything anywhere because it'll try to write to $HOME
00752        which is not what we want */
00753        pspell_config_replace(config, "save-repl", "false");
00754 
00755        ind = zend_list_insert(config, le_pspell_config);
00756        RETURN_LONG(ind);
00757 }
00758 /* }}} */
00759 
00760 /* {{{ proto bool pspell_config_runtogether(int conf, bool runtogether)
00761    Consider run-together words as valid components */
00762 static PHP_FUNCTION(pspell_config_runtogether)
00763 {
00764        int type;
00765        long conf;
00766        zend_bool runtogether;
00767        PspellConfig *config;
00768        
00769        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lb", &conf, &runtogether) == FAILURE) {
00770               return;
00771        }
00772 
00773        PSPELL_FETCH_CONFIG; 
00774 
00775        pspell_config_replace(config, "run-together", runtogether ? "true" : "false");
00776        
00777        RETURN_TRUE;
00778 }
00779 /* }}} */
00780 
00781 /* {{{ proto bool pspell_config_mode(int conf, long mode)
00782    Select mode for config (PSPELL_FAST, PSPELL_NORMAL or PSPELL_BAD_SPELLERS) */
00783 static PHP_FUNCTION(pspell_config_mode)
00784 {
00785        int type;
00786        long conf, mode;
00787        PspellConfig *config;
00788 
00789        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &conf, &mode) == FAILURE) {
00790               return;
00791        }
00792 
00793        PSPELL_FETCH_CONFIG;
00794 
00795        /* First check what mode we want (how many suggestions) */
00796        if (mode == PSPELL_FAST) {
00797               pspell_config_replace(config, "sug-mode", "fast");
00798        } else if (mode == PSPELL_NORMAL) {
00799               pspell_config_replace(config, "sug-mode", "normal");
00800        } else if (mode == PSPELL_BAD_SPELLERS) {
00801               pspell_config_replace(config, "sug-mode", "bad-spellers");
00802        }
00803 
00804        RETURN_TRUE;
00805 }
00806 /* }}} */
00807 
00808 /* {{{ proto bool pspell_config_ignore(int conf, int ignore)
00809    Ignore words <= n chars */
00810 static PHP_FUNCTION(pspell_config_ignore)
00811 {
00812        int type;
00813        char ignore_str[MAX_LENGTH_OF_LONG + 1];  
00814        long conf, ignore = 0L;
00815        PspellConfig *config;
00816        
00817        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &conf, &ignore) == FAILURE) {
00818               return;
00819        }
00820 
00821        PSPELL_FETCH_CONFIG;
00822 
00823        snprintf(ignore_str, sizeof(ignore_str), "%ld", ignore);
00824 
00825        pspell_config_replace(config, "ignore", ignore_str);
00826        RETURN_TRUE;
00827 }
00828 /* }}} */
00829 
00830 static void pspell_config_path(INTERNAL_FUNCTION_PARAMETERS, char *option)
00831 {
00832        int type;
00833        long conf;
00834        char *value;
00835        int value_len;
00836        PspellConfig *config;
00837        
00838        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &conf, &value, &value_len) == FAILURE) {
00839               return;
00840        }
00841 
00842        if (strlen(value) != value_len) {
00843               RETURN_FALSE;
00844        }
00845 
00846        PSPELL_FETCH_CONFIG;
00847 
00848        if (PG(safe_mode) && (!php_checkuid(value, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
00849               RETURN_FALSE;
00850        }
00851 
00852        if (php_check_open_basedir(value TSRMLS_CC)) {
00853               RETURN_FALSE;
00854        }
00855 
00856        pspell_config_replace(config, option, value);
00857 
00858        RETURN_TRUE;
00859 }
00860 
00861 /* {{{ proto bool pspell_config_personal(int conf, string personal)
00862    Use a personal dictionary for this config */
00863 static PHP_FUNCTION(pspell_config_personal)
00864 {
00865        pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "personal");
00866 }
00867 /* }}} */
00868 
00869 /* {{{ proto bool pspell_config_dict_dir(int conf, string directory)
00870    location of the main word list */
00871 static PHP_FUNCTION(pspell_config_dict_dir)
00872 {
00873        pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "dict-dir");
00874 }
00875 /* }}} */
00876 
00877 /* {{{ proto bool pspell_config_data_dir(int conf, string directory)
00878     location of language data files */
00879 static PHP_FUNCTION(pspell_config_data_dir)
00880 {
00881        pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "data-dir");
00882 }
00883 /* }}} */
00884 
00885 /* {{{ proto bool pspell_config_repl(int conf, string repl)
00886    Use a personal dictionary with replacement pairs for this config */
00887 static PHP_FUNCTION(pspell_config_repl)
00888 {
00889        int type;
00890        long conf;
00891        char *repl;
00892        int repl_len;
00893        PspellConfig *config;
00894        
00895        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &conf, &repl, &repl_len) == FAILURE) {
00896               return;
00897        }
00898 
00899        PSPELL_FETCH_CONFIG;
00900 
00901        pspell_config_replace(config, "save-repl", "true");
00902 
00903        if (strlen(repl) != repl_len) {
00904               RETURN_FALSE;
00905        }
00906 
00907        if (PG(safe_mode) && (!php_checkuid(repl, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
00908               RETURN_FALSE;
00909        }
00910 
00911        if (php_check_open_basedir(repl TSRMLS_CC)) {
00912               RETURN_FALSE;
00913        }
00914 
00915        pspell_config_replace(config, "repl", repl);
00916 
00917        RETURN_TRUE;
00918 }
00919 /* }}} */
00920 
00921 /* {{{ proto bool pspell_config_save_repl(int conf, bool save)
00922    Save replacement pairs when personal list is saved for this config */
00923 static PHP_FUNCTION(pspell_config_save_repl)
00924 {
00925        int type;
00926        long conf;
00927        zend_bool save;
00928        PspellConfig *config;
00929        
00930        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lb", &conf, &save) == FAILURE) {
00931               return;
00932        }
00933 
00934        PSPELL_FETCH_CONFIG;
00935 
00936        pspell_config_replace(config, "save-repl", save ? "true" : "false");
00937 
00938        RETURN_TRUE;
00939 }
00940 /* }}} */
00941 
00942 /* {{{ PHP_MINFO_FUNCTION
00943  */
00944 static PHP_MINFO_FUNCTION(pspell)
00945 {
00946        php_info_print_table_start();
00947        php_info_print_table_row(2, "PSpell Support", "enabled");
00948        php_info_print_table_end();
00949 }
00950 /* }}} */
00951 
00952 #endif
00953 
00954 /*
00955  * Local variables:
00956  * tab-width: 4
00957  * c-basic-offset: 4
00958  * End:
00959  * vim600: sw=4 ts=4 fdm=marker
00960  * vim<600: sw=4 ts=4
00961  */