Annotation of embedaddon/php/ext/pspell/pspell.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
                      5:    | Copyright (c) 1997-2012 The PHP Group                                |
                      6:    +----------------------------------------------------------------------+
                      7:    | This source file is subject to version 3.01 of the PHP license,      |
                      8:    | that is bundled with this package in the file LICENSE, and is        |
                      9:    | available through the world-wide-web at the following url:           |
                     10:    | http://www.php.net/license/3_01.txt                                  |
                     11:    | If you did not receive a copy of the PHP license and are unable to   |
                     12:    | obtain it through the world-wide-web, please send a note to          |
                     13:    | license@php.net so we can mail you a copy immediately.               |
                     14:    +----------------------------------------------------------------------+
                     15:    | Author: Vlad Krupin <phpdevel@echospace.com>                         |
                     16:    +----------------------------------------------------------------------+
                     17: */
                     18: 
                     19: /* $Id: pspell.c 321634 2012-01-01 13:15:04Z felipe $ */
                     20: 
                     21: #define IS_EXT_MODULE
                     22: 
                     23: #ifdef HAVE_CONFIG_H
                     24: #include "config.h"
                     25: #endif
                     26: 
                     27: #include "php.h"
                     28: 
                     29: #include <stdlib.h>
                     30: #include <ctype.h>
                     31: #include <stdio.h>
                     32: 
                     33: #if HAVE_PSPELL
                     34: 
                     35: /* this will enforce compatibility in .12 version (broken after .11.2) */
                     36: #define USE_ORIGINAL_MANAGER_FUNCS
                     37: 
                     38: #include "php_pspell.h"
                     39: #include <pspell.h>
                     40: #include "ext/standard/info.h"
                     41: 
                     42: #define PSPELL_FAST 1L
                     43: #define PSPELL_NORMAL 2L
                     44: #define PSPELL_BAD_SPELLERS 3L
                     45: #define PSPELL_SPEED_MASK_INTERNAL 3L
                     46: #define PSPELL_RUN_TOGETHER 8L
                     47: 
                     48: /* Largest ignored word can be 999 characters (this seems sane enough), 
                     49:  * and it takes 3 bytes to represent that (see pspell_config_ignore)
                     50:  */
                     51: #define PSPELL_LARGEST_WORD 3
                     52: 
                     53: static PHP_MINIT_FUNCTION(pspell);
                     54: static PHP_MINFO_FUNCTION(pspell);
                     55: static PHP_FUNCTION(pspell_new);
                     56: static PHP_FUNCTION(pspell_new_personal);
                     57: static PHP_FUNCTION(pspell_new_config);
                     58: static PHP_FUNCTION(pspell_check);
                     59: static PHP_FUNCTION(pspell_suggest);
                     60: static PHP_FUNCTION(pspell_store_replacement);
                     61: static PHP_FUNCTION(pspell_add_to_personal);
                     62: static PHP_FUNCTION(pspell_add_to_session);
                     63: static PHP_FUNCTION(pspell_clear_session);
                     64: static PHP_FUNCTION(pspell_save_wordlist);
                     65: static PHP_FUNCTION(pspell_config_create);
                     66: static PHP_FUNCTION(pspell_config_runtogether);
                     67: static PHP_FUNCTION(pspell_config_mode);
                     68: static PHP_FUNCTION(pspell_config_ignore);
                     69: static PHP_FUNCTION(pspell_config_personal);
                     70: static PHP_FUNCTION(pspell_config_dict_dir);
                     71: static PHP_FUNCTION(pspell_config_data_dir);
                     72: static PHP_FUNCTION(pspell_config_repl);
                     73: static PHP_FUNCTION(pspell_config_save_repl);
                     74: 
                     75: /* {{{ arginfo */
                     76: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_new, 0, 0, 1)
                     77:        ZEND_ARG_INFO(0, language)
                     78:        ZEND_ARG_INFO(0, spelling)
                     79:        ZEND_ARG_INFO(0, jargon)
                     80:        ZEND_ARG_INFO(0, encoding)
                     81:        ZEND_ARG_INFO(0, mode)
                     82: ZEND_END_ARG_INFO()
                     83: 
                     84: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_new_personal, 0, 0, 2)
                     85:        ZEND_ARG_INFO(0, personal)
                     86:        ZEND_ARG_INFO(0, language)
                     87:        ZEND_ARG_INFO(0, spelling)
                     88:        ZEND_ARG_INFO(0, jargon)
                     89:        ZEND_ARG_INFO(0, encoding)
                     90:        ZEND_ARG_INFO(0, mode)
                     91: ZEND_END_ARG_INFO()
                     92: 
                     93: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_new_config, 0, 0, 1)
                     94:        ZEND_ARG_INFO(0, config)
                     95: ZEND_END_ARG_INFO()
                     96: 
                     97: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_check, 0, 0, 2)
                     98:        ZEND_ARG_INFO(0, pspell)
                     99:        ZEND_ARG_INFO(0, word)
                    100: ZEND_END_ARG_INFO()
                    101: 
                    102: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_suggest, 0, 0, 2)
                    103:        ZEND_ARG_INFO(0, pspell)
                    104:        ZEND_ARG_INFO(0, word)
                    105: ZEND_END_ARG_INFO()
                    106: 
                    107: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_store_replacement, 0, 0, 3)
                    108:        ZEND_ARG_INFO(0, pspell)
                    109:        ZEND_ARG_INFO(0, misspell)
                    110:        ZEND_ARG_INFO(0, correct)
                    111: ZEND_END_ARG_INFO()
                    112: 
                    113: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_add_to_personal, 0, 0, 2)
                    114:        ZEND_ARG_INFO(0, pspell)
                    115:        ZEND_ARG_INFO(0, word)
                    116: ZEND_END_ARG_INFO()
                    117: 
                    118: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_add_to_session, 0, 0, 2)
                    119:        ZEND_ARG_INFO(0, pspell)
                    120:        ZEND_ARG_INFO(0, word)
                    121: ZEND_END_ARG_INFO()
                    122: 
                    123: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_clear_session, 0, 0, 1)
                    124:        ZEND_ARG_INFO(0, pspell)
                    125: ZEND_END_ARG_INFO()
                    126: 
                    127: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_save_wordlist, 0, 0, 1)
                    128:        ZEND_ARG_INFO(0, pspell)
                    129: ZEND_END_ARG_INFO()
                    130: 
                    131: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_create, 0, 0, 1)
                    132:        ZEND_ARG_INFO(0, language)
                    133:        ZEND_ARG_INFO(0, spelling)
                    134:        ZEND_ARG_INFO(0, jargon)
                    135:        ZEND_ARG_INFO(0, encoding)
                    136: ZEND_END_ARG_INFO()
                    137: 
                    138: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_runtogether, 0, 0, 2)
                    139:        ZEND_ARG_INFO(0, conf)
                    140:        ZEND_ARG_INFO(0, runtogether)
                    141: ZEND_END_ARG_INFO()
                    142: 
                    143: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_mode, 0, 0, 2)
                    144:        ZEND_ARG_INFO(0, conf)
                    145:        ZEND_ARG_INFO(0, mode)
                    146: ZEND_END_ARG_INFO()
                    147: 
                    148: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_ignore, 0, 0, 2)
                    149:        ZEND_ARG_INFO(0, conf)
                    150:        ZEND_ARG_INFO(0, ignore)
                    151: ZEND_END_ARG_INFO()
                    152: 
                    153: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_personal, 0, 0, 2)
                    154:        ZEND_ARG_INFO(0, conf)
                    155:        ZEND_ARG_INFO(0, personal)
                    156: ZEND_END_ARG_INFO()
                    157: 
                    158: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_dict_dir, 0, 0, 2)
                    159:        ZEND_ARG_INFO(0, conf)
                    160:        ZEND_ARG_INFO(0, directory)
                    161: ZEND_END_ARG_INFO()
                    162: 
                    163: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_data_dir, 0, 0, 2)
                    164:        ZEND_ARG_INFO(0, conf)
                    165:        ZEND_ARG_INFO(0, directory)
                    166: ZEND_END_ARG_INFO()
                    167: 
                    168: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_repl, 0, 0, 2)
                    169:        ZEND_ARG_INFO(0, conf)
                    170:        ZEND_ARG_INFO(0, repl)
                    171: ZEND_END_ARG_INFO()
                    172: 
                    173: ZEND_BEGIN_ARG_INFO_EX(arginfo_pspell_config_save_repl, 0, 0, 2)
                    174:        ZEND_ARG_INFO(0, conf)
                    175:        ZEND_ARG_INFO(0, save)
                    176: ZEND_END_ARG_INFO()
                    177: /* }}} */
                    178: 
                    179: /* {{{ pspell_functions[]
                    180:  */
                    181: static const zend_function_entry pspell_functions[] = {
                    182:        PHP_FE(pspell_new,                                      arginfo_pspell_new)
                    183:        PHP_FE(pspell_new_personal,                     arginfo_pspell_new_personal)
                    184:        PHP_FE(pspell_new_config,                       arginfo_pspell_new_config)
                    185:        PHP_FE(pspell_check,                            arginfo_pspell_check)
                    186:        PHP_FE(pspell_suggest,                          arginfo_pspell_suggest)
                    187:        PHP_FE(pspell_store_replacement,        arginfo_pspell_store_replacement)
                    188:        PHP_FE(pspell_add_to_personal,          arginfo_pspell_add_to_personal)
                    189:        PHP_FE(pspell_add_to_session,           arginfo_pspell_add_to_session)
                    190:        PHP_FE(pspell_clear_session,            arginfo_pspell_clear_session)
                    191:        PHP_FE(pspell_save_wordlist,            arginfo_pspell_save_wordlist)
                    192:        PHP_FE(pspell_config_create,            arginfo_pspell_config_create)
                    193:        PHP_FE(pspell_config_runtogether,       arginfo_pspell_config_runtogether)
                    194:        PHP_FE(pspell_config_mode,                      arginfo_pspell_config_mode)
                    195:        PHP_FE(pspell_config_ignore,            arginfo_pspell_config_ignore)
                    196:        PHP_FE(pspell_config_personal,          arginfo_pspell_config_personal)
                    197:        PHP_FE(pspell_config_dict_dir,          arginfo_pspell_config_dict_dir)
                    198:        PHP_FE(pspell_config_data_dir,          arginfo_pspell_config_data_dir)
                    199:        PHP_FE(pspell_config_repl,                      arginfo_pspell_config_repl)
                    200:        PHP_FE(pspell_config_save_repl,         arginfo_pspell_config_save_repl)
                    201:        PHP_FE_END
                    202: };
                    203: /* }}} */
                    204: 
                    205: static int le_pspell, le_pspell_config;
                    206: 
                    207: zend_module_entry pspell_module_entry = {
                    208:     STANDARD_MODULE_HEADER,
                    209:        "pspell", pspell_functions, PHP_MINIT(pspell), NULL, NULL, NULL, PHP_MINFO(pspell), NO_VERSION_YET, STANDARD_MODULE_PROPERTIES
                    210: };
                    211: 
                    212: #ifdef COMPILE_DL_PSPELL
                    213: ZEND_GET_MODULE(pspell)
                    214: #endif
                    215: 
                    216: static void php_pspell_close(zend_rsrc_list_entry *rsrc TSRMLS_DC)
                    217: {
                    218:        PspellManager *manager = (PspellManager *)rsrc->ptr;
                    219: 
                    220:        delete_pspell_manager(manager);
                    221: }
                    222: 
                    223: static void php_pspell_close_config(zend_rsrc_list_entry *rsrc TSRMLS_DC)
                    224: {
                    225:        PspellConfig *config = (PspellConfig *)rsrc->ptr;
                    226: 
                    227:        delete_pspell_config(config);
                    228: }
                    229: 
                    230: #define PSPELL_FETCH_CONFIG \
                    231:        config = (PspellConfig *) zend_list_find(conf, &type);  \
                    232:        if (config == NULL || type != le_pspell_config) {       \
                    233:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%ld is not a PSPELL config index", conf);  \
                    234:                RETURN_FALSE;   \
                    235:        }       \
                    236: 
                    237: #define PSPELL_FETCH_MANAGER \
                    238:        manager = (PspellManager *) zend_list_find(scin, &type);        \
                    239:        if (!manager || type != le_pspell) {    \
                    240:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%ld is not a PSPELL result index", scin);  \
                    241:                RETURN_FALSE;   \
                    242:        }       \
                    243: 
                    244: /* {{{ PHP_MINIT_FUNCTION
                    245:  */
                    246: static PHP_MINIT_FUNCTION(pspell)
                    247: {
                    248:        REGISTER_LONG_CONSTANT("PSPELL_FAST", PSPELL_FAST, CONST_PERSISTENT | CONST_CS);
                    249:        REGISTER_LONG_CONSTANT("PSPELL_NORMAL", PSPELL_NORMAL, CONST_PERSISTENT | CONST_CS);
                    250:        REGISTER_LONG_CONSTANT("PSPELL_BAD_SPELLERS", PSPELL_BAD_SPELLERS, CONST_PERSISTENT | CONST_CS);
                    251:        REGISTER_LONG_CONSTANT("PSPELL_RUN_TOGETHER", PSPELL_RUN_TOGETHER, CONST_PERSISTENT | CONST_CS);
                    252:        le_pspell = zend_register_list_destructors_ex(php_pspell_close, NULL, "pspell", module_number);
                    253:        le_pspell_config = zend_register_list_destructors_ex(php_pspell_close_config, NULL, "pspell config", module_number);
                    254:        return SUCCESS;
                    255: }
                    256: /* }}} */
                    257: 
                    258: /* {{{ proto int pspell_new(string language [, string spelling [, string jargon [, string encoding [, int mode]]]])
                    259:    Load a dictionary */
                    260: static PHP_FUNCTION(pspell_new)
                    261: {
                    262:        char *language, *spelling = NULL, *jargon = NULL, *encoding = NULL;
                    263:        int language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0;
                    264:        long mode = 0L,  speed = 0L;
                    265:        int argc = ZEND_NUM_ARGS();
                    266:        int ind;
                    267: 
                    268: #ifdef PHP_WIN32
                    269:        TCHAR aspell_dir[200];
                    270:        TCHAR data_dir[220];
                    271:        TCHAR dict_dir[220];
                    272:        HKEY hkey;
                    273:        DWORD dwType,dwLen;
                    274: #endif
                    275: 
                    276:        PspellCanHaveError *ret;
                    277:        PspellManager *manager;
                    278:        PspellConfig *config;
                    279:        
                    280:        if (zend_parse_parameters(argc TSRMLS_CC, "s|sssl", &language, &language_len, &spelling, &spelling_len,
                    281:                &jargon, &jargon_len, &encoding, &encoding_len, &mode) == FAILURE) {
                    282:                return;
                    283:        }
                    284: 
                    285:        config = new_pspell_config();
                    286: 
                    287: #ifdef PHP_WIN32
                    288:        /* If aspell was installed using installer, we should have a key
                    289:         * pointing to the location of the dictionaries
                    290:         */
                    291:        if (0 == RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Aspell", &hkey)) {
                    292:                LONG result;
                    293:                dwLen = sizeof(aspell_dir) - 1;
                    294:                result = RegQueryValueEx(hkey, "", NULL, &dwType, (LPBYTE)&aspell_dir, &dwLen);
                    295:                RegCloseKey(hkey);
                    296:                if (result == ERROR_SUCCESS) {
                    297:                        strlcpy(data_dir, aspell_dir, sizeof(data_dir));
                    298:                        strlcat(data_dir, "\\data", sizeof(data_dir));
                    299:                        strlcpy(dict_dir, aspell_dir, sizeof(dict_dir));
                    300:                        strlcat(dict_dir, "\\dict", sizeof(dict_dir));
                    301: 
                    302:                        pspell_config_replace(config, "data-dir", data_dir);
                    303:                        pspell_config_replace(config, "dict-dir", dict_dir);
                    304:                }
                    305:        }
                    306: #endif
                    307: 
                    308:        pspell_config_replace(config, "language-tag", language);
                    309: 
                    310:        if (spelling_len) {
                    311:                pspell_config_replace(config, "spelling", spelling);
                    312:        }
                    313: 
                    314:        if (jargon_len) {
                    315:                pspell_config_replace(config, "jargon", jargon);
                    316:        }
                    317: 
                    318:        if (encoding_len) {
                    319:                pspell_config_replace(config, "encoding", encoding);
                    320:        }
                    321: 
                    322:        if (argc > 4) {
                    323:                speed = mode & PSPELL_SPEED_MASK_INTERNAL;
                    324: 
                    325:                /* First check what mode we want (how many suggestions) */
                    326:                if (speed == PSPELL_FAST) {
                    327:                        pspell_config_replace(config, "sug-mode", "fast");
                    328:                } else if (speed == PSPELL_NORMAL) {
                    329:                        pspell_config_replace(config, "sug-mode", "normal");
                    330:                } else if (speed == PSPELL_BAD_SPELLERS) {
                    331:                        pspell_config_replace(config, "sug-mode", "bad-spellers");
                    332:                }
                    333:                
                    334:                /* Then we see if run-together words should be treated as valid components */
                    335:                if (mode & PSPELL_RUN_TOGETHER) {
                    336:                        pspell_config_replace(config, "run-together", "true");
                    337:                }
                    338:        }
                    339: 
                    340:        ret = new_pspell_manager(config);
                    341:        delete_pspell_config(config);
                    342: 
                    343:        if (pspell_error_number(ret) != 0) {
                    344:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret));
                    345:                delete_pspell_can_have_error(ret);
                    346:                RETURN_FALSE;
                    347:        }
                    348:        
                    349:        manager = to_pspell_manager(ret);
                    350:        ind = zend_list_insert(manager, le_pspell);
                    351:        RETURN_LONG(ind);
                    352: }
                    353: /* }}} */
                    354: 
                    355: /* {{{ proto int pspell_new_personal(string personal, string language [, string spelling [, string jargon [, string encoding [, int mode]]]])
                    356:    Load a dictionary with a personal wordlist*/
                    357: static PHP_FUNCTION(pspell_new_personal)
                    358: {
                    359:        char *personal, *language, *spelling = NULL, *jargon = NULL, *encoding = NULL;
                    360:        int personal_len, language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0;
                    361:        long mode = 0L,  speed = 0L;
                    362:        int argc = ZEND_NUM_ARGS();
                    363:        int ind;
                    364: 
                    365: #ifdef PHP_WIN32
                    366:        TCHAR aspell_dir[200];
                    367:        TCHAR data_dir[220];
                    368:        TCHAR dict_dir[220];
                    369:        HKEY hkey;
                    370:        DWORD dwType,dwLen;
                    371: #endif
                    372: 
                    373:        PspellCanHaveError *ret;
                    374:        PspellManager *manager;
                    375:        PspellConfig *config;
                    376: 
                    377:        if (zend_parse_parameters(argc TSRMLS_CC, "ss|sssl", &personal, &personal_len, &language, &language_len, 
                    378:                &spelling, &spelling_len, &jargon, &jargon_len, &encoding, &encoding_len, &mode) == FAILURE) {
                    379:                return;
                    380:        }
                    381: 
                    382:        config = new_pspell_config();
                    383: 
                    384: #ifdef PHP_WIN32
                    385:        /* If aspell was installed using installer, we should have a key
                    386:         * pointing to the location of the dictionaries
                    387:         */
                    388:        if (0 == RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Aspell", &hkey)) {
                    389:                LONG result;
                    390:                dwLen = sizeof(aspell_dir) - 1;
                    391:                result = RegQueryValueEx(hkey, "", NULL, &dwType, (LPBYTE)&aspell_dir, &dwLen);
                    392:                RegCloseKey(hkey);
                    393:                if (result == ERROR_SUCCESS) {
                    394:                        strlcpy(data_dir, aspell_dir, sizeof(data_dir));
                    395:                        strlcat(data_dir, "\\data", sizeof(data_dir));
                    396:                        strlcpy(dict_dir, aspell_dir, sizeof(dict_dir));
                    397:                        strlcat(dict_dir, "\\dict", sizeof(dict_dir));
                    398: 
                    399:                        pspell_config_replace(config, "data-dir", data_dir);
                    400:                        pspell_config_replace(config, "dict-dir", dict_dir);
                    401:                }
                    402:        }
                    403: #endif
                    404: 
                    405:        if (strlen(personal) != personal_len) {
                    406:                delete_pspell_config(config);
                    407:                RETURN_FALSE;
                    408:        }
                    409: 
                    410:        if (PG(safe_mode) && (!php_checkuid(personal, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
                    411:                delete_pspell_config(config);
                    412:                RETURN_FALSE;
                    413:        }
                    414: 
                    415:        if (php_check_open_basedir(personal TSRMLS_CC)) {
                    416:                delete_pspell_config(config);
                    417:                RETURN_FALSE;
                    418:        }
                    419: 
                    420:        pspell_config_replace(config, "personal", personal);
                    421:        pspell_config_replace(config, "save-repl", "false");
                    422: 
                    423:        pspell_config_replace(config, "language-tag", language);
                    424: 
                    425:        if (spelling_len) {
                    426:                pspell_config_replace(config, "spelling", spelling);
                    427:        }
                    428: 
                    429:        if (jargon_len) {
                    430:                pspell_config_replace(config, "jargon", jargon);
                    431:        }
                    432: 
                    433:        if (encoding_len) {
                    434:                pspell_config_replace(config, "encoding", encoding);
                    435:        }
                    436: 
                    437:        if (argc > 5) {
                    438:                speed = mode & PSPELL_SPEED_MASK_INTERNAL;
                    439: 
                    440:                /* First check what mode we want (how many suggestions) */
                    441:                if (speed == PSPELL_FAST) {
                    442:                        pspell_config_replace(config, "sug-mode", "fast");
                    443:                } else if (speed == PSPELL_NORMAL) {
                    444:                        pspell_config_replace(config, "sug-mode", "normal");
                    445:                } else if (speed == PSPELL_BAD_SPELLERS) {
                    446:                        pspell_config_replace(config, "sug-mode", "bad-spellers");
                    447:                }
                    448:                
                    449:                /* Then we see if run-together words should be treated as valid components */
                    450:                if (mode & PSPELL_RUN_TOGETHER) {
                    451:                        pspell_config_replace(config, "run-together", "true");
                    452:                }
                    453:        }
                    454: 
                    455:        ret = new_pspell_manager(config);
                    456:        delete_pspell_config(config);
                    457: 
                    458:        if (pspell_error_number(ret) != 0) {
                    459:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret));
                    460:                delete_pspell_can_have_error(ret);
                    461:                RETURN_FALSE;
                    462:        }
                    463:        
                    464:        manager = to_pspell_manager(ret);
                    465:        ind = zend_list_insert(manager, le_pspell);
                    466:        RETURN_LONG(ind);
                    467: }
                    468: /* }}} */
                    469: 
                    470: /* {{{ proto int pspell_new_config(int config)
                    471:    Load a dictionary based on the given config */
                    472: static PHP_FUNCTION(pspell_new_config)
                    473: {
                    474:        int type, ind;
                    475:        long conf;      
                    476:        PspellCanHaveError *ret;
                    477:        PspellManager *manager;
                    478:        PspellConfig *config;
                    479:        
                    480:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &conf) == FAILURE) {
                    481:                return;
                    482:        }
                    483: 
                    484:        PSPELL_FETCH_CONFIG;
                    485: 
                    486:        ret = new_pspell_manager(config);
                    487: 
                    488:        if (pspell_error_number(ret) != 0) {
                    489:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret));
                    490:                delete_pspell_can_have_error(ret);
                    491:                RETURN_FALSE;
                    492:        }
                    493:        
                    494:        manager = to_pspell_manager(ret);
                    495:        ind = zend_list_insert(manager, le_pspell);
                    496:        RETURN_LONG(ind);
                    497: }
                    498: /* }}} */
                    499: 
                    500: /* {{{ proto bool pspell_check(int pspell, string word)
                    501:    Returns true if word is valid */
                    502: static PHP_FUNCTION(pspell_check)
                    503: {
                    504:        int type, word_len;
                    505:        long scin;
                    506:        char *word;
                    507:        PspellManager *manager;
                    508: 
                    509:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &scin, &word, &word_len) == FAILURE) {
                    510:                return;
                    511:        }
                    512: 
                    513:        PSPELL_FETCH_MANAGER;
                    514: 
                    515:        if (pspell_manager_check(manager, word)) {
                    516:                RETURN_TRUE;
                    517:        } else {
                    518:                RETURN_FALSE;
                    519:        }
                    520: }
                    521: /* }}} */
                    522: 
                    523: /* {{{ proto array pspell_suggest(int pspell, string word)
                    524:    Returns array of suggestions */
                    525: static PHP_FUNCTION(pspell_suggest)
                    526: {
                    527:        long scin;
                    528:        char *word;
                    529:        int word_len;
                    530:        PspellManager *manager;
                    531:        int type;
                    532:        const PspellWordList *wl;
                    533:        const char *sug;
                    534: 
                    535:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &scin, &word, &word_len) == FAILURE) {
                    536:                return;
                    537:        }
                    538: 
                    539:        PSPELL_FETCH_MANAGER;
                    540: 
                    541:        array_init(return_value);
                    542: 
                    543:        wl = pspell_manager_suggest(manager, word);
                    544:        if (wl) {
                    545:                PspellStringEmulation *els = pspell_word_list_elements(wl);
                    546:                while ((sug = pspell_string_emulation_next(els)) != 0) {
                    547:                        add_next_index_string(return_value,(char *)sug,1);
                    548:                }
                    549:                delete_pspell_string_emulation(els);
                    550:        } else {
                    551:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "PSPELL had a problem. details: %s", pspell_manager_error_message(manager));
                    552:                RETURN_FALSE;
                    553:        }
                    554: }
                    555: /* }}} */
                    556: 
                    557: /* {{{ proto bool pspell_store_replacement(int pspell, string misspell, string correct)
                    558:    Notify the dictionary of a user-selected replacement */
                    559: static PHP_FUNCTION(pspell_store_replacement)
                    560: {
                    561:        int type, miss_len, corr_len;
                    562:        long scin;
                    563:        char *miss, *corr;
                    564:        PspellManager *manager;
                    565: 
                    566:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lss", &scin, &miss, &miss_len, &corr, &corr_len) == FAILURE) {
                    567:                return;
                    568:        }
                    569: 
                    570:        PSPELL_FETCH_MANAGER;
                    571: 
                    572:        pspell_manager_store_replacement(manager, miss, corr);
                    573:        if (pspell_manager_error_number(manager) == 0) {
                    574:                RETURN_TRUE;
                    575:        } else {
                    576:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "pspell_store_replacement() gave error: %s", pspell_manager_error_message(manager));
                    577:                RETURN_FALSE;
                    578:        }
                    579: }
                    580: /* }}} */
                    581: 
                    582: /* {{{ proto bool pspell_add_to_personal(int pspell, string word)
                    583:    Adds a word to a personal list */
                    584: static PHP_FUNCTION(pspell_add_to_personal)
                    585: {
                    586:        int type, word_len;
                    587:        long scin;
                    588:        char *word;
                    589:        PspellManager *manager;
                    590: 
                    591:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &scin, &word, &word_len) == FAILURE) {
                    592:                return;
                    593:        }
                    594: 
                    595:        PSPELL_FETCH_MANAGER;
                    596: 
                    597:        /*If the word is empty, we have to return; otherwise we'll segfault! ouch!*/
                    598:        if (word_len == 0) {
                    599:                RETURN_FALSE;
                    600:        }
                    601:        
                    602:        pspell_manager_add_to_personal(manager, word);
                    603:        if (pspell_manager_error_number(manager) == 0) {
                    604:                RETURN_TRUE;
                    605:        } else {
                    606:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "pspell_add_to_personal() gave error: %s", pspell_manager_error_message(manager));
                    607:                RETURN_FALSE;
                    608:        }
                    609: }
                    610: /* }}} */
                    611: 
                    612: /* {{{ proto bool pspell_add_to_session(int pspell, string word)
                    613:    Adds a word to the current session */
                    614: static PHP_FUNCTION(pspell_add_to_session)
                    615: {
                    616:        int type, word_len;
                    617:        long scin;
                    618:        char *word;
                    619:        PspellManager *manager;
                    620: 
                    621:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &scin, &word, &word_len) == FAILURE) {
                    622:                return;
                    623:        }
                    624: 
                    625:        PSPELL_FETCH_MANAGER;
                    626: 
                    627:        /*If the word is empty, we have to return; otherwise we'll segfault! ouch!*/
                    628:        if (word_len == 0) {
                    629:                RETURN_FALSE;
                    630:        }
                    631: 
                    632:        pspell_manager_add_to_session(manager, word);
                    633:        if (pspell_manager_error_number(manager) == 0) {
                    634:                RETURN_TRUE;
                    635:        } else {
                    636:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "pspell_add_to_session() gave error: %s", pspell_manager_error_message(manager));
                    637:                RETURN_FALSE;
                    638:        }
                    639: }
                    640: /* }}} */
                    641: 
                    642: /* {{{ proto bool pspell_clear_session(int pspell)
                    643:    Clears the current session */
                    644: static PHP_FUNCTION(pspell_clear_session)
                    645: {
                    646:        int type;
                    647:        long scin;
                    648:        PspellManager *manager;
                    649: 
                    650:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &scin) == FAILURE) {
                    651:                return;
                    652:        }
                    653:     
                    654:        PSPELL_FETCH_MANAGER;   
                    655: 
                    656:        pspell_manager_clear_session(manager);
                    657:        if (pspell_manager_error_number(manager) == 0) {
                    658:                RETURN_TRUE;
                    659:        } else {
                    660:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "pspell_clear_session() gave error: %s", pspell_manager_error_message(manager));
                    661:                RETURN_FALSE;
                    662:        }
                    663: }
                    664: /* }}} */
                    665: 
                    666: /* {{{ proto bool pspell_save_wordlist(int pspell)
                    667:    Saves the current (personal) wordlist */
                    668: static PHP_FUNCTION(pspell_save_wordlist)
                    669: {
                    670:        int type;
                    671:        long scin;
                    672:        PspellManager *manager;
                    673: 
                    674:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &scin) == FAILURE) {
                    675:                return;
                    676:        }
                    677:     
                    678:        PSPELL_FETCH_MANAGER;   
                    679: 
                    680:        pspell_manager_save_all_word_lists(manager);
                    681: 
                    682:        if (pspell_manager_error_number(manager) == 0) {
                    683:                RETURN_TRUE;
                    684:        } else {
                    685:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "pspell_save_wordlist() gave error: %s", pspell_manager_error_message(manager));
                    686:                RETURN_FALSE;
                    687:        }
                    688: 
                    689: }
                    690: /* }}} */
                    691: 
                    692: /* {{{ proto int pspell_config_create(string language [, string spelling [, string jargon [, string encoding]]])
                    693:    Create a new config to be used later to create a manager */
                    694: static PHP_FUNCTION(pspell_config_create)
                    695: {
                    696:        char *language, *spelling = NULL, *jargon = NULL, *encoding = NULL;
                    697:        int language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0;
                    698:        int ind;
                    699:        PspellConfig *config;
                    700: 
                    701: #ifdef PHP_WIN32
                    702:        TCHAR aspell_dir[200];
                    703:        TCHAR data_dir[220];
                    704:        TCHAR dict_dir[220];
                    705:        HKEY hkey;
                    706:        DWORD dwType,dwLen;
                    707: #endif
                    708:        
                    709:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sss", &language, &language_len, &spelling, &spelling_len, 
                    710:                &jargon, &jargon_len, &encoding, &encoding_len) == FAILURE) {
                    711:                return;
                    712:        }
                    713: 
                    714:        config = new_pspell_config();
                    715: 
                    716: #ifdef PHP_WIN32
                    717:     /* If aspell was installed using installer, we should have a key
                    718:      * pointing to the location of the dictionaries
                    719:      */
                    720:        if (0 == RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Aspell", &hkey)) {
                    721:                LONG result;
                    722:                dwLen = sizeof(aspell_dir) - 1;
                    723:                result = RegQueryValueEx(hkey, "", NULL, &dwType, (LPBYTE)&aspell_dir, &dwLen);
                    724:                RegCloseKey(hkey);
                    725:                if (result == ERROR_SUCCESS) {
                    726:                        strlcpy(data_dir, aspell_dir, sizeof(data_dir));
                    727:                        strlcat(data_dir, "\\data", sizeof(data_dir));
                    728:                        strlcpy(dict_dir, aspell_dir, sizeof(dict_dir));
                    729:                        strlcat(dict_dir, "\\dict", sizeof(dict_dir));
                    730: 
                    731:                        pspell_config_replace(config, "data-dir", data_dir);
                    732:                        pspell_config_replace(config, "dict-dir", dict_dir);
                    733:                }
                    734:        }
                    735: #endif
                    736: 
                    737:        pspell_config_replace(config, "language-tag", language);
                    738: 
                    739:        if (spelling_len) {
                    740:                pspell_config_replace(config, "spelling", spelling);
                    741:        }
                    742: 
                    743:        if (jargon_len) {
                    744:                pspell_config_replace(config, "jargon", jargon);
                    745:        }
                    746: 
                    747:        if (encoding_len) {
                    748:                pspell_config_replace(config, "encoding", encoding);
                    749:        }
                    750: 
                    751:        /* By default I do not want to write anything anywhere because it'll try to write to $HOME
                    752:        which is not what we want */
                    753:        pspell_config_replace(config, "save-repl", "false");
                    754: 
                    755:        ind = zend_list_insert(config, le_pspell_config);
                    756:        RETURN_LONG(ind);
                    757: }
                    758: /* }}} */
                    759: 
                    760: /* {{{ proto bool pspell_config_runtogether(int conf, bool runtogether)
                    761:    Consider run-together words as valid components */
                    762: static PHP_FUNCTION(pspell_config_runtogether)
                    763: {
                    764:        int type;
                    765:        long conf;
                    766:        zend_bool runtogether;
                    767:        PspellConfig *config;
                    768:        
                    769:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lb", &conf, &runtogether) == FAILURE) {
                    770:                return;
                    771:        }
                    772: 
                    773:        PSPELL_FETCH_CONFIG;    
                    774: 
                    775:        pspell_config_replace(config, "run-together", runtogether ? "true" : "false");
                    776:        
                    777:        RETURN_TRUE;
                    778: }
                    779: /* }}} */
                    780: 
                    781: /* {{{ proto bool pspell_config_mode(int conf, long mode)
                    782:    Select mode for config (PSPELL_FAST, PSPELL_NORMAL or PSPELL_BAD_SPELLERS) */
                    783: static PHP_FUNCTION(pspell_config_mode)
                    784: {
                    785:        int type;
                    786:        long conf, mode;
                    787:        PspellConfig *config;
                    788: 
                    789:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &conf, &mode) == FAILURE) {
                    790:                return;
                    791:        }
                    792: 
                    793:        PSPELL_FETCH_CONFIG;
                    794: 
                    795:        /* First check what mode we want (how many suggestions) */
                    796:        if (mode == PSPELL_FAST) {
                    797:                pspell_config_replace(config, "sug-mode", "fast");
                    798:        } else if (mode == PSPELL_NORMAL) {
                    799:                pspell_config_replace(config, "sug-mode", "normal");
                    800:        } else if (mode == PSPELL_BAD_SPELLERS) {
                    801:                pspell_config_replace(config, "sug-mode", "bad-spellers");
                    802:        }
                    803: 
                    804:        RETURN_TRUE;
                    805: }
                    806: /* }}} */
                    807: 
                    808: /* {{{ proto bool pspell_config_ignore(int conf, int ignore)
                    809:    Ignore words <= n chars */
                    810: static PHP_FUNCTION(pspell_config_ignore)
                    811: {
                    812:        int type;
                    813:        char ignore_str[MAX_LENGTH_OF_LONG + 1];        
                    814:        long conf, ignore = 0L;
                    815:        PspellConfig *config;
                    816:        
                    817:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &conf, &ignore) == FAILURE) {
                    818:                return;
                    819:        }
                    820: 
                    821:        PSPELL_FETCH_CONFIG;
                    822: 
                    823:        snprintf(ignore_str, sizeof(ignore_str), "%ld", ignore);
                    824: 
                    825:        pspell_config_replace(config, "ignore", ignore_str);
                    826:        RETURN_TRUE;
                    827: }
                    828: /* }}} */
                    829: 
                    830: static void pspell_config_path(INTERNAL_FUNCTION_PARAMETERS, char *option)
                    831: {
                    832:        int type;
                    833:        long conf;
                    834:        char *value;
                    835:        int value_len;
                    836:        PspellConfig *config;
                    837:        
                    838:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &conf, &value, &value_len) == FAILURE) {
                    839:                return;
                    840:        }
                    841: 
                    842:        if (strlen(value) != value_len) {
                    843:                RETURN_FALSE;
                    844:        }
                    845: 
                    846:        PSPELL_FETCH_CONFIG;
                    847: 
                    848:        if (PG(safe_mode) && (!php_checkuid(value, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
                    849:                RETURN_FALSE;
                    850:        }
                    851: 
                    852:        if (php_check_open_basedir(value TSRMLS_CC)) {
                    853:                RETURN_FALSE;
                    854:        }
                    855: 
                    856:        pspell_config_replace(config, option, value);
                    857: 
                    858:        RETURN_TRUE;
                    859: }
                    860: 
                    861: /* {{{ proto bool pspell_config_personal(int conf, string personal)
                    862:    Use a personal dictionary for this config */
                    863: static PHP_FUNCTION(pspell_config_personal)
                    864: {
                    865:        pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "personal");
                    866: }
                    867: /* }}} */
                    868: 
                    869: /* {{{ proto bool pspell_config_dict_dir(int conf, string directory)
                    870:    location of the main word list */
                    871: static PHP_FUNCTION(pspell_config_dict_dir)
                    872: {
                    873:        pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "dict-dir");
                    874: }
                    875: /* }}} */
                    876: 
                    877: /* {{{ proto bool pspell_config_data_dir(int conf, string directory)
                    878:     location of language data files */
                    879: static PHP_FUNCTION(pspell_config_data_dir)
                    880: {
                    881:        pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "data-dir");
                    882: }
                    883: /* }}} */
                    884: 
                    885: /* {{{ proto bool pspell_config_repl(int conf, string repl)
                    886:    Use a personal dictionary with replacement pairs for this config */
                    887: static PHP_FUNCTION(pspell_config_repl)
                    888: {
                    889:        int type;
                    890:        long conf;
                    891:        char *repl;
                    892:        int repl_len;
                    893:        PspellConfig *config;
                    894:        
                    895:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &conf, &repl, &repl_len) == FAILURE) {
                    896:                return;
                    897:        }
                    898: 
                    899:        PSPELL_FETCH_CONFIG;
                    900: 
                    901:        pspell_config_replace(config, "save-repl", "true");
                    902: 
                    903:        if (strlen(repl) != repl_len) {
                    904:                RETURN_FALSE;
                    905:        }
                    906: 
                    907:        if (PG(safe_mode) && (!php_checkuid(repl, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
                    908:                RETURN_FALSE;
                    909:        }
                    910: 
                    911:        if (php_check_open_basedir(repl TSRMLS_CC)) {
                    912:                RETURN_FALSE;
                    913:        }
                    914: 
                    915:        pspell_config_replace(config, "repl", repl);
                    916: 
                    917:        RETURN_TRUE;
                    918: }
                    919: /* }}} */
                    920: 
                    921: /* {{{ proto bool pspell_config_save_repl(int conf, bool save)
                    922:    Save replacement pairs when personal list is saved for this config */
                    923: static PHP_FUNCTION(pspell_config_save_repl)
                    924: {
                    925:        int type;
                    926:        long conf;
                    927:        zend_bool save;
                    928:        PspellConfig *config;
                    929:        
                    930:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lb", &conf, &save) == FAILURE) {
                    931:                return;
                    932:        }
                    933: 
                    934:        PSPELL_FETCH_CONFIG;
                    935: 
                    936:        pspell_config_replace(config, "save-repl", save ? "true" : "false");
                    937: 
                    938:        RETURN_TRUE;
                    939: }
                    940: /* }}} */
                    941: 
                    942: /* {{{ PHP_MINFO_FUNCTION
                    943:  */
                    944: static PHP_MINFO_FUNCTION(pspell)
                    945: {
                    946:        php_info_print_table_start();
                    947:        php_info_print_table_row(2, "PSpell Support", "enabled");
                    948:        php_info_print_table_end();
                    949: }
                    950: /* }}} */
                    951: 
                    952: #endif
                    953: 
                    954: /*
                    955:  * Local variables:
                    956:  * tab-width: 4
                    957:  * c-basic-offset: 4
                    958:  * End:
                    959:  * vim600: sw=4 ts=4 fdm=marker
                    960:  * vim<600: sw=4 ts=4
                    961:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>