├── CREDITS ├── tests ├── wordlist.txt ├── 004.phpt ├── 002.phpt ├── 003.phpt ├── 005.phpt └── 001.phpt ├── config.w32 ├── .gitignore ├── config.m4 ├── php_pspell.h ├── package.xml ├── pspell.stub.php ├── LICENSE ├── pspell_arginfo.h └── pspell.c /CREDITS: -------------------------------------------------------------------------------- 1 | Pspell 2 | Vlad Krupin 3 | -------------------------------------------------------------------------------- /tests/wordlist.txt: -------------------------------------------------------------------------------- 1 | personal_ws-1.1 en 4 2 | dfnvnsafksfksf 3 | fg 4 | iufrsn 5 | jsksjfsjf 6 | -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | // vim:ft=javascript 2 | 3 | ARG_WITH("pspell", "pspell/aspell (whatever it's called this month) support", "no"); 4 | 5 | if (PHP_PSPELL != "no") { 6 | 7 | if (CHECK_HEADER_ADD_INCLUDE("pspell.h", "CFLAGS_PSPELL", PHP_PHP_BUILD + "\\include\\pspell;" + PHP_PSPELL) && 8 | CHECK_LIB("aspell*.lib", "pspell", PHP_PSPELL)) { 9 | EXTENSION('pspell', 'pspell.c'); 10 | AC_DEFINE('HAVE_PSPELL', 1); 11 | } else { 12 | WARNING("pspell not enabled; libraries and headers not found"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile.global 2 | acinclude.m4 3 | aclocal.m4 4 | autom4te.cache 5 | build 6 | config.guess 7 | config.h.in 8 | config.sub 9 | configure 10 | configure.in 11 | install-sh 12 | ltmain.sh 13 | missing 14 | mkinstalldirs 15 | run-tests.php 16 | .deps 17 | Makefile 18 | Makefile.fragments 19 | Makefile.objects 20 | config.h 21 | config.log 22 | config.nice 23 | config.status 24 | libtool 25 | .idea 26 | CMakeLists.txt 27 | .libs 28 | pspell.la 29 | pspell.lo 30 | pspell.so 31 | /*~ 32 | configure.ac 33 | php_test_* 34 | pspell-*.tgz 35 | pspell.dep 36 | -------------------------------------------------------------------------------- /tests/004.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | pspell configs 3 | --EXTENSIONS-- 4 | pspell 5 | --SKIPIF-- 6 | 9 | --FILE-- 10 | 27 | --EXPECT-- 28 | bool(true) 29 | bool(true) 30 | bool(false) 31 | --- 32 | bool(true) 33 | bool(true) 34 | -------------------------------------------------------------------------------- /tests/002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | pspell session 3 | --EXTENSIONS-- 4 | pspell 5 | --SKIPIF-- 6 | 9 | --FILE-- 10 | 29 | --EXPECT-- 30 | bool(false) 31 | bool(false) 32 | bool(true) 33 | bool(true) 34 | bool(true) 35 | bool(false) 36 | -------------------------------------------------------------------------------- /tests/003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | pspell_config_ignore 3 | --EXTENSIONS-- 4 | pspell 5 | --SKIPIF-- 6 | 9 | --FILE-- 10 | getMessage() . "\n"; 23 | } 24 | 25 | echo "---\n"; 26 | var_dump(pspell_config_ignore($cfg, 2)); 27 | $p = pspell_new_config($cfg); 28 | var_dump(pspell_check($p, 'yy')); 29 | 30 | // segfault it? 31 | var_dump(pspell_config_ignore($cfg, PHP_INT_MAX)); 32 | 33 | ?> 34 | --EXPECTF-- 35 | bool(false) 36 | 37 | Warning: pspell_new_config(): PSPELL couldn't open the dictionary. reason: The encoding "b0rked" is not known. This could also mean that the file "%sb0rked.%s" could not be opened for reading or does not exist. in %s003.php on line 9 38 | pspell_check(): Argument #1 ($dictionary) must be of type PSpell\Dictionary, %s given 39 | --- 40 | bool(true) 41 | bool(true) 42 | bool(true) 43 | -------------------------------------------------------------------------------- /tests/005.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | pspell configs 3 | --EXTENSIONS-- 4 | pspell 5 | --SKIPIF-- 6 | 10 | --FILE-- 11 | 37 | --EXPECTF-- 38 | Warning: pspell_new_personal(): PSPELL couldn't open the dictionary. reason: The file "%s005.php" is not in the proper format. in %s005.php on line 5 39 | bool(false) 40 | bool(true) 41 | -- 42 | bool(true) 43 | bool(false) 44 | bool(true) 45 | bool(true) 46 | -- 47 | bool(true) 48 | bool(true) 49 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | PHP_ARG_WITH([pspell], 2 | [for PSPELL support], 3 | [AS_HELP_STRING([[--with-pspell[=DIR]]], 4 | [Include PSPELL support. GNU Aspell version 0.50.0 or higher required])]) 5 | 6 | if test "$PHP_PSPELL" != "no"; then 7 | dnl Add -Wno-strict-prototypes as depends on user libs 8 | PHP_NEW_EXTENSION(pspell, pspell.c, $ext_shared, , "-Wno-strict-prototypes") 9 | if test "$PHP_PSPELL" != "yes"; then 10 | PSPELL_SEARCH_DIRS=$PHP_PSPELL 11 | else 12 | PSPELL_SEARCH_DIRS="/usr/local /usr" 13 | fi 14 | for i in $PSPELL_SEARCH_DIRS; do 15 | if test -f $i/include/pspell/pspell.h; then 16 | PSPELL_DIR=$i 17 | PSPELL_INCDIR=$i/include/pspell 18 | elif test -f $i/include/pspell.h; then 19 | PSPELL_DIR=$i 20 | PSPELL_INCDIR=$i/include 21 | fi 22 | done 23 | 24 | if test -z "$PSPELL_DIR"; then 25 | AC_MSG_ERROR(Cannot find pspell) 26 | fi 27 | 28 | PSPELL_LIBDIR=$PSPELL_DIR/$PHP_LIBDIR 29 | 30 | PHP_ADD_LIBRARY_WITH_PATH(pspell, $PSPELL_LIBDIR, PSPELL_SHARED_LIBADD) 31 | 32 | dnl Add -laspell to LIBS if it exists 33 | PHP_CHECK_LIBRARY(aspell,new_aspell_config, 34 | [ 35 | PHP_ADD_LIBRARY_WITH_PATH(aspell, $PSPELL_LIBDIR, PSPELL_SHARED_LIBADD) 36 | ], [], [ 37 | -L$PSPELL_LIBDIR 38 | ]) 39 | 40 | PHP_ADD_INCLUDE($PSPELL_INCDIR) 41 | PHP_SUBST(PSPELL_SHARED_LIBADD) 42 | AC_DEFINE(HAVE_PSPELL,1,[ ]) 43 | fi 44 | -------------------------------------------------------------------------------- /php_pspell.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Copyright (c) The PHP Group | 4 | +----------------------------------------------------------------------+ 5 | | This source file is subject to version 3.01 of the PHP license, | 6 | | that is bundled with this package in the file LICENSE, and is | 7 | | available through the world-wide-web at the following url: | 8 | | https://www.php.net/license/3_01.txt | 9 | | If you did not receive a copy of the PHP license and are unable to | 10 | | obtain it through the world-wide-web, please send a note to | 11 | | license@php.net so we can mail you a copy immediately. | 12 | +----------------------------------------------------------------------+ 13 | | Author: Vlad Krupin | 14 | +----------------------------------------------------------------------+ 15 | */ 16 | 17 | #ifndef _PSPELL_H 18 | #define _PSPELL_H 19 | #ifdef HAVE_PSPELL 20 | extern zend_module_entry pspell_module_entry; 21 | #define pspell_module_ptr &pspell_module_entry 22 | 23 | #include "php_version.h" 24 | #define PHP_PSPELL_VERSION "1.0.1" 25 | 26 | #else 27 | #define pspell_module_ptr NULL 28 | #endif 29 | 30 | #define phpext_pspell_ptr pspell_module_ptr 31 | 32 | #endif /* _PSPELL_H */ 33 | -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | pspell 7 | pecl.php.net 8 | This extension allows you to check the spelling of a word and offer suggestions. 9 | 10 | This extension allows you to check the spelling of a word and offer suggestions. 11 | 12 | 13 | Derick Rethans 14 | derick 15 | derick@php.net 16 | yes 17 | 18 | 2023-11-23 19 | 20 | 21 | 1.0.1 22 | 1.0.0 23 | 24 | 25 | stable 26 | stable 27 | 28 | PHP 3.01 29 | 30 | - Fixed version (don't use PHP version) and tests. 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 8.1.0 56 | 57 | 58 | 1.4.0b1 59 | 60 | 61 | 62 | pspell 63 | 64 | 65 | -------------------------------------------------------------------------------- /pspell.stub.php: -------------------------------------------------------------------------------- 1 | |false 58 | * @refcount 1 59 | */ 60 | function pspell_suggest(PSpell\Dictionary $dictionary, string $word): array|false {} 61 | function pspell_store_replacement(PSpell\Dictionary $dictionary, string $misspelled, string $correct): bool {} 62 | function pspell_add_to_personal(PSpell\Dictionary $dictionary, string $word): bool {} 63 | function pspell_add_to_session(PSpell\Dictionary $dictionary, string $word): bool {} 64 | function pspell_clear_session(PSpell\Dictionary $dictionary): bool {} 65 | function pspell_save_wordlist(PSpell\Dictionary $dictionary): bool {} 66 | 67 | function pspell_config_create(string $language, string $spelling = "", string $jargon = "", string $encoding = ""): PSpell\Config {} 68 | function pspell_config_runtogether(PSpell\Config $config, bool $allow): bool {} 69 | function pspell_config_mode(PSpell\Config $config, int $mode): bool {} 70 | function pspell_config_ignore(PSpell\Config $config, int $min_length): bool {} 71 | function pspell_config_personal(PSpell\Config $config, string $filename): bool {} 72 | function pspell_config_dict_dir(PSpell\Config $config, string $directory): bool {} 73 | function pspell_config_data_dir(PSpell\Config $config, string $directory): bool {} 74 | function pspell_config_repl(PSpell\Config $config, string $filename): bool {} 75 | function pspell_config_save_repl(PSpell\Config $config, bool $save): bool {} 76 | 77 | } 78 | -------------------------------------------------------------------------------- /tests/001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | pspell basic tests (warning: may fail with pspell/aspell < GNU Aspell 0.50.3) 3 | --EXTENSIONS-- 4 | pspell 5 | --SKIPIF-- 6 | 11 | --FILE-- 12 | 39 | --EXPECTF-- 40 | I : true 41 | will : true 42 | not : true 43 | buy : true 44 | this : true 45 | record : true 46 | it : true 47 | is : true 48 | scratched : true 49 | Sorry : true 50 | I : true 51 | will : true 52 | not : true 53 | buy : true 54 | this : true 55 | record : true 56 | it : true 57 | is : true 58 | scratched : true 59 | Uh : true 60 | no : true 61 | no : true 62 | no : true 63 | This : true 64 | is : true 65 | a : true 66 | tobacconists : true 67 | Ah : true 68 | I : true 69 | will : true 70 | not : true 71 | buy : true 72 | this : true 73 | tobacconists : true 74 | it : true 75 | is : true 76 | scratched : true 77 | No : true 78 | no : true 79 | no : true 80 | no : true 81 | Tobacco : true 82 | um : true 83 | cigarettes : true 84 | holds : true 85 | up : true 86 | a : true 87 | pack : true 88 | Ya : true 89 | Seegarets : ..false 90 | Possible spellings:%s,Regrets,%s,Cigarettes,%s 91 | Ya : true 92 | Uh : true 93 | My : true 94 | hovercraft : true 95 | is : true 96 | full : true 97 | of : true 98 | eels : true 99 | Sorry : true 100 | My : true 101 | hovercraft : true 102 | pantomimes : true 103 | puffing : true 104 | a : true 105 | cigarette : true 106 | is : true 107 | full : true 108 | of : true 109 | eels : true 110 | pretends : true 111 | to : true 112 | strike : true 113 | a : true 114 | match : true 115 | Ahh : ..false 116 | Possible spellings:%sAh,Aha,%s 117 | matches : true 118 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------- 2 | The PHP License, version 3.01 3 | Copyright (c) 1999 - 2023 The PHP Group. All rights reserved. 4 | -------------------------------------------------------------------- 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, is permitted provided that the following conditions 8 | are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in 15 | the documentation and/or other materials provided with the 16 | distribution. 17 | 18 | 3. The name "PHP" must not be used to endorse or promote products 19 | derived from this software without prior written permission. For 20 | written permission, please contact group@php.net. 21 | 22 | 4. Products derived from this software may not be called "PHP", nor 23 | may "PHP" appear in their name, without prior written permission 24 | from group@php.net. You may indicate that your software works in 25 | conjunction with PHP by saying "Foo for PHP" instead of calling 26 | it "PHP Foo" or "phpfoo" 27 | 28 | 5. The PHP Group may publish revised and/or new versions of the 29 | license from time to time. Each version will be given a 30 | distinguishing version number. 31 | Once covered code has been published under a particular version 32 | of the license, you may always continue to use it under the terms 33 | of that version. You may also choose to use such covered code 34 | under the terms of any subsequent version of the license 35 | published by the PHP Group. No one other than the PHP Group has 36 | the right to modify the terms applicable to covered code created 37 | under this License. 38 | 39 | 6. Redistributions of any form whatsoever must retain the following 40 | acknowledgment: 41 | "This product includes PHP software, freely available from 42 | ". 43 | 44 | THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND 45 | ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 46 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 47 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP 48 | DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 49 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 50 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 51 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 53 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 54 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 55 | OF THE POSSIBILITY OF SUCH DAMAGE. 56 | 57 | -------------------------------------------------------------------- 58 | 59 | This software consists of voluntary contributions made by many 60 | individuals on behalf of the PHP Group. 61 | 62 | The PHP Group can be contacted via Email at group@php.net. 63 | 64 | For more information on the PHP Group and the PHP project, 65 | please see . 66 | 67 | PHP includes the Zend Engine, freely available at 68 | . 69 | -------------------------------------------------------------------------------- /pspell_arginfo.h: -------------------------------------------------------------------------------- 1 | /* This is a generated file, edit the .stub.php file instead. 2 | * Stub hash: 8d35f61a0b48c5422b31e78f587d9258fd3e8e37 */ 3 | 4 | ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_pspell_new, 0, 1, PSpell\\Dictionary, MAY_BE_FALSE) 5 | ZEND_ARG_TYPE_INFO(0, language, IS_STRING, 0) 6 | ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, spelling, IS_STRING, 0, "\"\"") 7 | ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, jargon, IS_STRING, 0, "\"\"") 8 | ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encoding, IS_STRING, 0, "\"\"") 9 | ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "0") 10 | ZEND_END_ARG_INFO() 11 | 12 | ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_pspell_new_personal, 0, 2, PSpell\\Dictionary, MAY_BE_FALSE) 13 | ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) 14 | ZEND_ARG_TYPE_INFO(0, language, IS_STRING, 0) 15 | ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, spelling, IS_STRING, 0, "\"\"") 16 | ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, jargon, IS_STRING, 0, "\"\"") 17 | ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encoding, IS_STRING, 0, "\"\"") 18 | ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "0") 19 | ZEND_END_ARG_INFO() 20 | 21 | ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_pspell_new_config, 0, 1, PSpell\\Dictionary, MAY_BE_FALSE) 22 | ZEND_ARG_OBJ_INFO(0, config, PSpell\\Config, 0) 23 | ZEND_END_ARG_INFO() 24 | 25 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pspell_check, 0, 2, _IS_BOOL, 0) 26 | ZEND_ARG_OBJ_INFO(0, dictionary, PSpell\\Dictionary, 0) 27 | ZEND_ARG_TYPE_INFO(0, word, IS_STRING, 0) 28 | ZEND_END_ARG_INFO() 29 | 30 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_pspell_suggest, 0, 2, MAY_BE_ARRAY|MAY_BE_FALSE) 31 | ZEND_ARG_OBJ_INFO(0, dictionary, PSpell\\Dictionary, 0) 32 | ZEND_ARG_TYPE_INFO(0, word, IS_STRING, 0) 33 | ZEND_END_ARG_INFO() 34 | 35 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pspell_store_replacement, 0, 3, _IS_BOOL, 0) 36 | ZEND_ARG_OBJ_INFO(0, dictionary, PSpell\\Dictionary, 0) 37 | ZEND_ARG_TYPE_INFO(0, misspelled, IS_STRING, 0) 38 | ZEND_ARG_TYPE_INFO(0, correct, IS_STRING, 0) 39 | ZEND_END_ARG_INFO() 40 | 41 | #define arginfo_pspell_add_to_personal arginfo_pspell_check 42 | 43 | #define arginfo_pspell_add_to_session arginfo_pspell_check 44 | 45 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pspell_clear_session, 0, 1, _IS_BOOL, 0) 46 | ZEND_ARG_OBJ_INFO(0, dictionary, PSpell\\Dictionary, 0) 47 | ZEND_END_ARG_INFO() 48 | 49 | #define arginfo_pspell_save_wordlist arginfo_pspell_clear_session 50 | 51 | ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_pspell_config_create, 0, 1, PSpell\\Config, 0) 52 | ZEND_ARG_TYPE_INFO(0, language, IS_STRING, 0) 53 | ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, spelling, IS_STRING, 0, "\"\"") 54 | ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, jargon, IS_STRING, 0, "\"\"") 55 | ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encoding, IS_STRING, 0, "\"\"") 56 | ZEND_END_ARG_INFO() 57 | 58 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pspell_config_runtogether, 0, 2, _IS_BOOL, 0) 59 | ZEND_ARG_OBJ_INFO(0, config, PSpell\\Config, 0) 60 | ZEND_ARG_TYPE_INFO(0, allow, _IS_BOOL, 0) 61 | ZEND_END_ARG_INFO() 62 | 63 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pspell_config_mode, 0, 2, _IS_BOOL, 0) 64 | ZEND_ARG_OBJ_INFO(0, config, PSpell\\Config, 0) 65 | ZEND_ARG_TYPE_INFO(0, mode, IS_LONG, 0) 66 | ZEND_END_ARG_INFO() 67 | 68 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pspell_config_ignore, 0, 2, _IS_BOOL, 0) 69 | ZEND_ARG_OBJ_INFO(0, config, PSpell\\Config, 0) 70 | ZEND_ARG_TYPE_INFO(0, min_length, IS_LONG, 0) 71 | ZEND_END_ARG_INFO() 72 | 73 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pspell_config_personal, 0, 2, _IS_BOOL, 0) 74 | ZEND_ARG_OBJ_INFO(0, config, PSpell\\Config, 0) 75 | ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) 76 | ZEND_END_ARG_INFO() 77 | 78 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pspell_config_dict_dir, 0, 2, _IS_BOOL, 0) 79 | ZEND_ARG_OBJ_INFO(0, config, PSpell\\Config, 0) 80 | ZEND_ARG_TYPE_INFO(0, directory, IS_STRING, 0) 81 | ZEND_END_ARG_INFO() 82 | 83 | #define arginfo_pspell_config_data_dir arginfo_pspell_config_dict_dir 84 | 85 | #define arginfo_pspell_config_repl arginfo_pspell_config_personal 86 | 87 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pspell_config_save_repl, 0, 2, _IS_BOOL, 0) 88 | ZEND_ARG_OBJ_INFO(0, config, PSpell\\Config, 0) 89 | ZEND_ARG_TYPE_INFO(0, save, _IS_BOOL, 0) 90 | ZEND_END_ARG_INFO() 91 | 92 | 93 | ZEND_FUNCTION(pspell_new); 94 | ZEND_FUNCTION(pspell_new_personal); 95 | ZEND_FUNCTION(pspell_new_config); 96 | ZEND_FUNCTION(pspell_check); 97 | ZEND_FUNCTION(pspell_suggest); 98 | ZEND_FUNCTION(pspell_store_replacement); 99 | ZEND_FUNCTION(pspell_add_to_personal); 100 | ZEND_FUNCTION(pspell_add_to_session); 101 | ZEND_FUNCTION(pspell_clear_session); 102 | ZEND_FUNCTION(pspell_save_wordlist); 103 | ZEND_FUNCTION(pspell_config_create); 104 | ZEND_FUNCTION(pspell_config_runtogether); 105 | ZEND_FUNCTION(pspell_config_mode); 106 | ZEND_FUNCTION(pspell_config_ignore); 107 | ZEND_FUNCTION(pspell_config_personal); 108 | ZEND_FUNCTION(pspell_config_dict_dir); 109 | ZEND_FUNCTION(pspell_config_data_dir); 110 | ZEND_FUNCTION(pspell_config_repl); 111 | ZEND_FUNCTION(pspell_config_save_repl); 112 | 113 | 114 | static const zend_function_entry ext_functions[] = { 115 | ZEND_FE(pspell_new, arginfo_pspell_new) 116 | ZEND_FE(pspell_new_personal, arginfo_pspell_new_personal) 117 | ZEND_FE(pspell_new_config, arginfo_pspell_new_config) 118 | ZEND_FE(pspell_check, arginfo_pspell_check) 119 | ZEND_FE(pspell_suggest, arginfo_pspell_suggest) 120 | ZEND_FE(pspell_store_replacement, arginfo_pspell_store_replacement) 121 | ZEND_FE(pspell_add_to_personal, arginfo_pspell_add_to_personal) 122 | ZEND_FE(pspell_add_to_session, arginfo_pspell_add_to_session) 123 | ZEND_FE(pspell_clear_session, arginfo_pspell_clear_session) 124 | ZEND_FE(pspell_save_wordlist, arginfo_pspell_save_wordlist) 125 | ZEND_FE(pspell_config_create, arginfo_pspell_config_create) 126 | ZEND_FE(pspell_config_runtogether, arginfo_pspell_config_runtogether) 127 | ZEND_FE(pspell_config_mode, arginfo_pspell_config_mode) 128 | ZEND_FE(pspell_config_ignore, arginfo_pspell_config_ignore) 129 | ZEND_FE(pspell_config_personal, arginfo_pspell_config_personal) 130 | ZEND_FE(pspell_config_dict_dir, arginfo_pspell_config_dict_dir) 131 | ZEND_FE(pspell_config_data_dir, arginfo_pspell_config_data_dir) 132 | ZEND_FE(pspell_config_repl, arginfo_pspell_config_repl) 133 | ZEND_FE(pspell_config_save_repl, arginfo_pspell_config_save_repl) 134 | ZEND_FE_END 135 | }; 136 | 137 | 138 | static const zend_function_entry class_PSpell_Dictionary_methods[] = { 139 | ZEND_FE_END 140 | }; 141 | 142 | 143 | static const zend_function_entry class_PSpell_Config_methods[] = { 144 | ZEND_FE_END 145 | }; 146 | 147 | static void register_pspell_symbols(int module_number) 148 | { 149 | REGISTER_LONG_CONSTANT("PSPELL_FAST", PSPELL_FAST, CONST_PERSISTENT); 150 | REGISTER_LONG_CONSTANT("PSPELL_NORMAL", PSPELL_NORMAL, CONST_PERSISTENT); 151 | REGISTER_LONG_CONSTANT("PSPELL_BAD_SPELLERS", PSPELL_BAD_SPELLERS, CONST_PERSISTENT); 152 | REGISTER_LONG_CONSTANT("PSPELL_RUN_TOGETHER", PSPELL_RUN_TOGETHER, CONST_PERSISTENT); 153 | } 154 | 155 | static zend_class_entry *register_class_PSpell_Dictionary(void) 156 | { 157 | zend_class_entry ce, *class_entry; 158 | 159 | INIT_NS_CLASS_ENTRY(ce, "PSpell", "Dictionary", class_PSpell_Dictionary_methods); 160 | class_entry = zend_register_internal_class_ex(&ce, NULL); 161 | class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE; 162 | 163 | return class_entry; 164 | } 165 | 166 | static zend_class_entry *register_class_PSpell_Config(void) 167 | { 168 | zend_class_entry ce, *class_entry; 169 | 170 | INIT_NS_CLASS_ENTRY(ce, "PSpell", "Config", class_PSpell_Config_methods); 171 | class_entry = zend_register_internal_class_ex(&ce, NULL); 172 | class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE; 173 | 174 | return class_entry; 175 | } 176 | -------------------------------------------------------------------------------- /pspell.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Copyright (c) The PHP Group | 4 | +----------------------------------------------------------------------+ 5 | | This source file is subject to version 3.01 of the PHP license, | 6 | | that is bundled with this package in the file LICENSE, and is | 7 | | available through the world-wide-web at the following url: | 8 | | https://www.php.net/license/3_01.txt | 9 | | If you did not receive a copy of the PHP license and are unable to | 10 | | obtain it through the world-wide-web, please send a note to | 11 | | license@php.net so we can mail you a copy immediately. | 12 | +----------------------------------------------------------------------+ 13 | | Author: Vlad Krupin | 14 | +----------------------------------------------------------------------+ 15 | */ 16 | 17 | #ifdef HAVE_CONFIG_H 18 | #include "config.h" 19 | #endif 20 | 21 | #include "php.h" 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #ifdef HAVE_PSPELL 28 | 29 | /* this will enforce compatibility in .12 version (broken after .11.2) */ 30 | #define USE_ORIGINAL_MANAGER_FUNCS 31 | 32 | #include "php_pspell.h" 33 | #include 34 | #include "ext/standard/info.h" 35 | 36 | #define PSPELL_FAST 1L 37 | #define PSPELL_NORMAL 2L 38 | #define PSPELL_BAD_SPELLERS 3L 39 | #define PSPELL_SPEED_MASK_INTERNAL 3L 40 | #define PSPELL_RUN_TOGETHER 8L 41 | 42 | #include "pspell_arginfo.h" 43 | 44 | /* Largest ignored word can be 999 characters (this seems sane enough), 45 | * and it takes 3 bytes to represent that (see pspell_config_ignore) 46 | */ 47 | #define PSPELL_LARGEST_WORD 3 48 | 49 | static PHP_MINIT_FUNCTION(pspell); 50 | static PHP_MINFO_FUNCTION(pspell); 51 | 52 | static zend_class_entry *php_pspell_ce = NULL; 53 | static zend_object_handlers php_pspell_handlers; 54 | static zend_class_entry *php_pspell_config_ce = NULL; 55 | static zend_object_handlers php_pspell_config_handlers; 56 | 57 | zend_module_entry pspell_module_entry = { 58 | STANDARD_MODULE_HEADER, 59 | "pspell", 60 | ext_functions, 61 | PHP_MINIT(pspell), 62 | NULL, 63 | NULL, 64 | NULL, 65 | PHP_MINFO(pspell), 66 | PHP_PSPELL_VERSION, 67 | STANDARD_MODULE_PROPERTIES, 68 | }; 69 | 70 | #ifdef COMPILE_DL_PSPELL 71 | ZEND_GET_MODULE(pspell) 72 | #endif 73 | 74 | /* class PSpell */ 75 | 76 | typedef struct _php_pspell_object { 77 | PspellManager *mgr; 78 | zend_object std; 79 | } php_pspell_object; 80 | 81 | static php_pspell_object *php_pspell_object_from_zend_object(zend_object *zobj) { 82 | return ((php_pspell_object*)(zobj + 1)) - 1; 83 | } 84 | 85 | static zend_object *php_pspell_object_to_zend_object(php_pspell_object *obj) { 86 | return ((zend_object*)(obj + 1)) - 1; 87 | } 88 | 89 | static zend_function *php_pspell_object_get_constructor(zend_object *object) 90 | { 91 | zend_throw_error(NULL, "You cannot initialize a PSpell\\Dictionary object except through helper functions"); 92 | return NULL; 93 | } 94 | 95 | static zend_object *php_pspell_object_create(zend_class_entry *ce) 96 | { 97 | php_pspell_object *obj = zend_object_alloc(sizeof(php_pspell_object), ce); 98 | zend_object *zobj = php_pspell_object_to_zend_object(obj); 99 | 100 | obj->mgr = NULL; 101 | zend_object_std_init(zobj, ce); 102 | object_properties_init(zobj, ce); 103 | zobj->handlers = &php_pspell_handlers; 104 | 105 | return zobj; 106 | } 107 | 108 | static void php_pspell_object_free(zend_object *zobj) { 109 | delete_pspell_manager(php_pspell_object_from_zend_object(zobj)->mgr); 110 | } 111 | 112 | /* class PSpellConfig */ 113 | 114 | typedef struct _php_pspell_config_object { 115 | PspellConfig *cfg; 116 | zend_object std; 117 | } php_pspell_config_object; 118 | 119 | static php_pspell_config_object *php_pspell_config_object_from_zend_object(zend_object *zobj) { 120 | return ((php_pspell_config_object*)(zobj + 1)) - 1; 121 | } 122 | 123 | static zend_object *php_pspell_config_object_to_zend_object(php_pspell_config_object *obj) { 124 | return ((zend_object*)(obj + 1)) - 1; 125 | } 126 | 127 | static zend_function *php_pspell_config_object_get_constructor(zend_object *object) 128 | { 129 | zend_throw_error(NULL, "You cannot initialize a PSpell\\Config object except through helper functions"); 130 | return NULL; 131 | } 132 | 133 | static zend_object *php_pspell_config_object_create(zend_class_entry *ce) 134 | { 135 | php_pspell_config_object *obj = zend_object_alloc(sizeof(php_pspell_config_object), ce); 136 | zend_object *zobj = php_pspell_config_object_to_zend_object(obj); 137 | 138 | obj->cfg = NULL; 139 | zend_object_std_init(zobj, ce); 140 | object_properties_init(zobj, ce); 141 | zobj->handlers = &php_pspell_config_handlers; 142 | 143 | return zobj; 144 | } 145 | 146 | static void php_pspell_config_object_free(zend_object *zobj) { 147 | delete_pspell_config(php_pspell_config_object_from_zend_object(zobj)->cfg); 148 | } 149 | 150 | /* {{{ PHP_MINIT_FUNCTION */ 151 | static PHP_MINIT_FUNCTION(pspell) 152 | { 153 | php_pspell_ce = register_class_PSpell_Dictionary(); 154 | php_pspell_ce->create_object = php_pspell_object_create; 155 | 156 | memcpy(&php_pspell_handlers, &std_object_handlers, sizeof(zend_object_handlers)); 157 | php_pspell_handlers.clone_obj = NULL; 158 | php_pspell_handlers.free_obj = php_pspell_object_free; 159 | php_pspell_handlers.get_constructor = php_pspell_object_get_constructor; 160 | php_pspell_handlers.offset = XtOffsetOf(php_pspell_object, std); 161 | 162 | php_pspell_config_ce = register_class_PSpell_Config(); 163 | php_pspell_config_ce->create_object = php_pspell_config_object_create; 164 | 165 | memcpy(&php_pspell_config_handlers, &std_object_handlers, sizeof(zend_object_handlers)); 166 | php_pspell_config_handlers.clone_obj = NULL; 167 | php_pspell_config_handlers.free_obj = php_pspell_config_object_free; 168 | php_pspell_config_handlers.get_constructor = php_pspell_config_object_get_constructor; 169 | php_pspell_config_handlers.offset = XtOffsetOf(php_pspell_config_object, std); 170 | 171 | register_pspell_symbols(module_number); 172 | 173 | return SUCCESS; 174 | } 175 | /* }}} */ 176 | 177 | /* {{{ Load a dictionary */ 178 | PHP_FUNCTION(pspell_new) 179 | { 180 | char *language, *spelling = NULL, *jargon = NULL, *encoding = NULL; 181 | size_t language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0; 182 | zend_long mode = Z_L(0), speed = Z_L(0); 183 | int argc = ZEND_NUM_ARGS(); 184 | 185 | #ifdef PHP_WIN32 186 | TCHAR aspell_dir[200]; 187 | TCHAR data_dir[220]; 188 | TCHAR dict_dir[220]; 189 | HKEY hkey; 190 | DWORD dwType,dwLen; 191 | #endif 192 | 193 | PspellCanHaveError *ret; 194 | PspellConfig *config; 195 | 196 | if (zend_parse_parameters(argc, "s|sssl", &language, &language_len, &spelling, &spelling_len, 197 | &jargon, &jargon_len, &encoding, &encoding_len, &mode) == FAILURE) { 198 | RETURN_THROWS(); 199 | } 200 | 201 | config = new_pspell_config(); 202 | 203 | #ifdef PHP_WIN32 204 | /* If aspell was installed using installer, we should have a key 205 | * pointing to the location of the dictionaries 206 | */ 207 | if (0 == RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Aspell", &hkey)) { 208 | LONG result; 209 | dwLen = sizeof(aspell_dir) - 1; 210 | result = RegQueryValueEx(hkey, "", NULL, &dwType, (LPBYTE)&aspell_dir, &dwLen); 211 | RegCloseKey(hkey); 212 | if (result == ERROR_SUCCESS) { 213 | strlcpy(data_dir, aspell_dir, sizeof(data_dir)); 214 | strlcat(data_dir, "\\data", sizeof(data_dir)); 215 | strlcpy(dict_dir, aspell_dir, sizeof(dict_dir)); 216 | strlcat(dict_dir, "\\dict", sizeof(dict_dir)); 217 | 218 | pspell_config_replace(config, "data-dir", data_dir); 219 | pspell_config_replace(config, "dict-dir", dict_dir); 220 | } 221 | } 222 | #endif 223 | 224 | pspell_config_replace(config, "language-tag", language); 225 | 226 | if (spelling_len) { 227 | pspell_config_replace(config, "spelling", spelling); 228 | } 229 | 230 | if (jargon_len) { 231 | pspell_config_replace(config, "jargon", jargon); 232 | } 233 | 234 | if (encoding_len) { 235 | pspell_config_replace(config, "encoding", encoding); 236 | } 237 | 238 | if (mode) { 239 | speed = mode & PSPELL_SPEED_MASK_INTERNAL; 240 | 241 | /* First check what mode we want (how many suggestions) */ 242 | if (speed == PSPELL_FAST) { 243 | pspell_config_replace(config, "sug-mode", "fast"); 244 | } else if (speed == PSPELL_NORMAL) { 245 | pspell_config_replace(config, "sug-mode", "normal"); 246 | } else if (speed == PSPELL_BAD_SPELLERS) { 247 | pspell_config_replace(config, "sug-mode", "bad-spellers"); 248 | } 249 | 250 | /* Then we see if run-together words should be treated as valid components */ 251 | if (mode & PSPELL_RUN_TOGETHER) { 252 | pspell_config_replace(config, "run-together", "true"); 253 | } 254 | } 255 | 256 | ret = new_pspell_manager(config); 257 | delete_pspell_config(config); 258 | 259 | if (pspell_error_number(ret) != 0) { 260 | php_error_docref(NULL, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret)); 261 | delete_pspell_can_have_error(ret); 262 | RETURN_FALSE; 263 | } 264 | 265 | object_init_ex(return_value, php_pspell_ce); 266 | php_pspell_object_from_zend_object(Z_OBJ_P(return_value))->mgr = to_pspell_manager(ret); 267 | } 268 | /* }}} */ 269 | 270 | /* {{{ Load a dictionary with a personal wordlist*/ 271 | PHP_FUNCTION(pspell_new_personal) 272 | { 273 | char *personal, *language, *spelling = NULL, *jargon = NULL, *encoding = NULL; 274 | size_t personal_len, language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0; 275 | zend_long mode = Z_L(0), speed = Z_L(0); 276 | int argc = ZEND_NUM_ARGS(); 277 | 278 | #ifdef PHP_WIN32 279 | TCHAR aspell_dir[200]; 280 | TCHAR data_dir[220]; 281 | TCHAR dict_dir[220]; 282 | HKEY hkey; 283 | DWORD dwType,dwLen; 284 | #endif 285 | 286 | PspellCanHaveError *ret; 287 | PspellConfig *config; 288 | 289 | if (zend_parse_parameters(argc, "ps|sssl", &personal, &personal_len, &language, &language_len, 290 | &spelling, &spelling_len, &jargon, &jargon_len, &encoding, &encoding_len, &mode) == FAILURE) { 291 | RETURN_THROWS(); 292 | } 293 | 294 | config = new_pspell_config(); 295 | 296 | #ifdef PHP_WIN32 297 | /* If aspell was installed using installer, we should have a key 298 | * pointing to the location of the dictionaries 299 | */ 300 | if (0 == RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Aspell", &hkey)) { 301 | LONG result; 302 | dwLen = sizeof(aspell_dir) - 1; 303 | result = RegQueryValueEx(hkey, "", NULL, &dwType, (LPBYTE)&aspell_dir, &dwLen); 304 | RegCloseKey(hkey); 305 | if (result == ERROR_SUCCESS) { 306 | strlcpy(data_dir, aspell_dir, sizeof(data_dir)); 307 | strlcat(data_dir, "\\data", sizeof(data_dir)); 308 | strlcpy(dict_dir, aspell_dir, sizeof(dict_dir)); 309 | strlcat(dict_dir, "\\dict", sizeof(dict_dir)); 310 | 311 | pspell_config_replace(config, "data-dir", data_dir); 312 | pspell_config_replace(config, "dict-dir", dict_dir); 313 | } 314 | } 315 | #endif 316 | 317 | if (php_check_open_basedir(personal)) { 318 | delete_pspell_config(config); 319 | RETURN_FALSE; 320 | } 321 | 322 | pspell_config_replace(config, "personal", personal); 323 | pspell_config_replace(config, "save-repl", "false"); 324 | 325 | pspell_config_replace(config, "language-tag", language); 326 | 327 | if (spelling_len) { 328 | pspell_config_replace(config, "spelling", spelling); 329 | } 330 | 331 | if (jargon_len) { 332 | pspell_config_replace(config, "jargon", jargon); 333 | } 334 | 335 | if (encoding_len) { 336 | pspell_config_replace(config, "encoding", encoding); 337 | } 338 | 339 | if (mode) { 340 | speed = mode & PSPELL_SPEED_MASK_INTERNAL; 341 | 342 | /* First check what mode we want (how many suggestions) */ 343 | if (speed == PSPELL_FAST) { 344 | pspell_config_replace(config, "sug-mode", "fast"); 345 | } else if (speed == PSPELL_NORMAL) { 346 | pspell_config_replace(config, "sug-mode", "normal"); 347 | } else if (speed == PSPELL_BAD_SPELLERS) { 348 | pspell_config_replace(config, "sug-mode", "bad-spellers"); 349 | } 350 | 351 | /* Then we see if run-together words should be treated as valid components */ 352 | if (mode & PSPELL_RUN_TOGETHER) { 353 | pspell_config_replace(config, "run-together", "true"); 354 | } 355 | } 356 | 357 | ret = new_pspell_manager(config); 358 | delete_pspell_config(config); 359 | 360 | if (pspell_error_number(ret) != 0) { 361 | php_error_docref(NULL, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret)); 362 | delete_pspell_can_have_error(ret); 363 | RETURN_FALSE; 364 | } 365 | 366 | object_init_ex(return_value, php_pspell_ce); 367 | php_pspell_object_from_zend_object(Z_OBJ_P(return_value))->mgr = to_pspell_manager(ret); 368 | } 369 | /* }}} */ 370 | 371 | /* {{{ Load a dictionary based on the given config */ 372 | PHP_FUNCTION(pspell_new_config) 373 | { 374 | zval *zcfg; 375 | PspellCanHaveError *ret; 376 | PspellConfig *config; 377 | 378 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zcfg, php_pspell_config_ce) == FAILURE) { 379 | RETURN_THROWS(); 380 | } 381 | config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg; 382 | 383 | ret = new_pspell_manager(config); 384 | 385 | if (pspell_error_number(ret) != 0) { 386 | php_error_docref(NULL, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret)); 387 | delete_pspell_can_have_error(ret); 388 | RETURN_FALSE; 389 | } 390 | 391 | object_init_ex(return_value, php_pspell_ce); 392 | php_pspell_object_from_zend_object(Z_OBJ_P(return_value))->mgr = to_pspell_manager(ret); 393 | } 394 | /* }}} */ 395 | 396 | /* {{{ Returns true if word is valid */ 397 | PHP_FUNCTION(pspell_check) 398 | { 399 | zval *zmgr; 400 | zend_string *word; 401 | PspellManager *manager; 402 | 403 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS", &zmgr, php_pspell_ce, &word) == FAILURE) { 404 | RETURN_THROWS(); 405 | } 406 | manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr; 407 | 408 | if (pspell_manager_check(manager, ZSTR_VAL(word))) { 409 | RETURN_TRUE; 410 | } else { 411 | RETURN_FALSE; 412 | } 413 | } 414 | /* }}} */ 415 | 416 | /* {{{ Returns array of suggestions */ 417 | PHP_FUNCTION(pspell_suggest) 418 | { 419 | zval *zmgr; 420 | zend_string *word; 421 | PspellManager *manager; 422 | const PspellWordList *wl; 423 | const char *sug; 424 | 425 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS", &zmgr, php_pspell_ce, &word) == FAILURE) { 426 | RETURN_THROWS(); 427 | } 428 | manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr; 429 | 430 | array_init(return_value); 431 | 432 | wl = pspell_manager_suggest(manager, ZSTR_VAL(word)); 433 | if (wl) { 434 | PspellStringEmulation *els = pspell_word_list_elements(wl); 435 | while ((sug = pspell_string_emulation_next(els)) != 0) { 436 | add_next_index_string(return_value,(char *)sug); 437 | } 438 | delete_pspell_string_emulation(els); 439 | } else { 440 | php_error_docref(NULL, E_WARNING, "PSPELL had a problem. details: %s", pspell_manager_error_message(manager)); 441 | RETURN_FALSE; 442 | } 443 | } 444 | /* }}} */ 445 | 446 | /* {{{ Notify the dictionary of a user-selected replacement */ 447 | PHP_FUNCTION(pspell_store_replacement) 448 | { 449 | zval *zmgr; 450 | zend_string *miss, *corr; 451 | PspellManager *manager; 452 | 453 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "OSS", &zmgr, php_pspell_ce, &miss, &corr) == FAILURE) { 454 | RETURN_THROWS(); 455 | } 456 | manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr; 457 | 458 | pspell_manager_store_replacement(manager, ZSTR_VAL(miss), ZSTR_VAL(corr)); 459 | if (pspell_manager_error_number(manager) == 0) { 460 | RETURN_TRUE; 461 | } else { 462 | php_error_docref(NULL, E_WARNING, "pspell_store_replacement() gave error: %s", pspell_manager_error_message(manager)); 463 | RETURN_FALSE; 464 | } 465 | } 466 | /* }}} */ 467 | 468 | /* {{{ Adds a word to a personal list */ 469 | PHP_FUNCTION(pspell_add_to_personal) 470 | { 471 | zval *zmgr; 472 | zend_string *word; 473 | PspellManager *manager; 474 | 475 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS", &zmgr, php_pspell_ce, &word) == FAILURE) { 476 | RETURN_THROWS(); 477 | } 478 | manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr; 479 | 480 | /*If the word is empty, we have to return; otherwise we'll segfault! ouch!*/ 481 | if (ZSTR_LEN(word) == 0) { 482 | RETURN_FALSE; 483 | } 484 | 485 | pspell_manager_add_to_personal(manager, ZSTR_VAL(word)); 486 | if (pspell_manager_error_number(manager) == 0) { 487 | RETURN_TRUE; 488 | } else { 489 | php_error_docref(NULL, E_WARNING, "pspell_add_to_personal() gave error: %s", pspell_manager_error_message(manager)); 490 | RETURN_FALSE; 491 | } 492 | } 493 | /* }}} */ 494 | 495 | /* {{{ Adds a word to the current session */ 496 | PHP_FUNCTION(pspell_add_to_session) 497 | { 498 | zval *zmgr; 499 | zend_string *word; 500 | PspellManager *manager; 501 | 502 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS", &zmgr, php_pspell_ce, &word) == FAILURE) { 503 | RETURN_THROWS(); 504 | } 505 | manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr; 506 | 507 | /*If the word is empty, we have to return; otherwise we'll segfault! ouch!*/ 508 | if (ZSTR_LEN(word) == 0) { 509 | RETURN_FALSE; 510 | } 511 | 512 | pspell_manager_add_to_session(manager, ZSTR_VAL(word)); 513 | if (pspell_manager_error_number(manager) == 0) { 514 | RETURN_TRUE; 515 | } else { 516 | php_error_docref(NULL, E_WARNING, "pspell_add_to_session() gave error: %s", pspell_manager_error_message(manager)); 517 | RETURN_FALSE; 518 | } 519 | } 520 | /* }}} */ 521 | 522 | /* {{{ Clears the current session */ 523 | PHP_FUNCTION(pspell_clear_session) 524 | { 525 | zval *zmgr; 526 | PspellManager *manager; 527 | 528 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zmgr, php_pspell_ce) == FAILURE) { 529 | RETURN_THROWS(); 530 | } 531 | manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr; 532 | 533 | pspell_manager_clear_session(manager); 534 | if (pspell_manager_error_number(manager) == 0) { 535 | RETURN_TRUE; 536 | } else { 537 | php_error_docref(NULL, E_WARNING, "pspell_clear_session() gave error: %s", pspell_manager_error_message(manager)); 538 | RETURN_FALSE; 539 | } 540 | } 541 | /* }}} */ 542 | 543 | /* {{{ Saves the current (personal) wordlist */ 544 | PHP_FUNCTION(pspell_save_wordlist) 545 | { 546 | zval *zmgr; 547 | PspellManager *manager; 548 | 549 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zmgr, php_pspell_ce) == FAILURE) { 550 | RETURN_THROWS(); 551 | } 552 | manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr; 553 | 554 | pspell_manager_save_all_word_lists(manager); 555 | 556 | if (pspell_manager_error_number(manager) == 0) { 557 | RETURN_TRUE; 558 | } else { 559 | php_error_docref(NULL, E_WARNING, "pspell_save_wordlist() gave error: %s", pspell_manager_error_message(manager)); 560 | RETURN_FALSE; 561 | } 562 | 563 | } 564 | /* }}} */ 565 | 566 | /* {{{ Create a new config to be used later to create a manager */ 567 | PHP_FUNCTION(pspell_config_create) 568 | { 569 | char *language, *spelling = NULL, *jargon = NULL, *encoding = NULL; 570 | size_t language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0; 571 | PspellConfig *config; 572 | 573 | #ifdef PHP_WIN32 574 | TCHAR aspell_dir[200]; 575 | TCHAR data_dir[220]; 576 | TCHAR dict_dir[220]; 577 | HKEY hkey; 578 | DWORD dwType,dwLen; 579 | #endif 580 | 581 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|sss", &language, &language_len, &spelling, &spelling_len, 582 | &jargon, &jargon_len, &encoding, &encoding_len) == FAILURE) { 583 | RETURN_THROWS(); 584 | } 585 | 586 | config = new_pspell_config(); 587 | 588 | #ifdef PHP_WIN32 589 | /* If aspell was installed using installer, we should have a key 590 | * pointing to the location of the dictionaries 591 | */ 592 | if (0 == RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Aspell", &hkey)) { 593 | LONG result; 594 | dwLen = sizeof(aspell_dir) - 1; 595 | result = RegQueryValueEx(hkey, "", NULL, &dwType, (LPBYTE)&aspell_dir, &dwLen); 596 | RegCloseKey(hkey); 597 | if (result == ERROR_SUCCESS) { 598 | strlcpy(data_dir, aspell_dir, sizeof(data_dir)); 599 | strlcat(data_dir, "\\data", sizeof(data_dir)); 600 | strlcpy(dict_dir, aspell_dir, sizeof(dict_dir)); 601 | strlcat(dict_dir, "\\dict", sizeof(dict_dir)); 602 | 603 | pspell_config_replace(config, "data-dir", data_dir); 604 | pspell_config_replace(config, "dict-dir", dict_dir); 605 | } 606 | } 607 | #endif 608 | 609 | pspell_config_replace(config, "language-tag", language); 610 | 611 | if (spelling_len) { 612 | pspell_config_replace(config, "spelling", spelling); 613 | } 614 | 615 | if (jargon_len) { 616 | pspell_config_replace(config, "jargon", jargon); 617 | } 618 | 619 | if (encoding_len) { 620 | pspell_config_replace(config, "encoding", encoding); 621 | } 622 | 623 | /* By default I do not want to write anything anywhere because it'll try to write to $HOME 624 | which is not what we want */ 625 | pspell_config_replace(config, "save-repl", "false"); 626 | 627 | object_init_ex(return_value, php_pspell_config_ce); 628 | php_pspell_config_object_from_zend_object(Z_OBJ_P(return_value))->cfg = config; 629 | } 630 | /* }}} */ 631 | 632 | /* {{{ Consider run-together words as valid components */ 633 | PHP_FUNCTION(pspell_config_runtogether) 634 | { 635 | zval *zcfg; 636 | bool runtogether; 637 | PspellConfig *config; 638 | 639 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ob", &zcfg, php_pspell_config_ce, &runtogether) == FAILURE) { 640 | RETURN_THROWS(); 641 | } 642 | config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg; 643 | 644 | pspell_config_replace(config, "run-together", runtogether ? "true" : "false"); 645 | 646 | RETURN_TRUE; 647 | } 648 | /* }}} */ 649 | 650 | /* {{{ Select mode for config (PSPELL_FAST, PSPELL_NORMAL or PSPELL_BAD_SPELLERS) */ 651 | PHP_FUNCTION(pspell_config_mode) 652 | { 653 | zval *zcfg; 654 | zend_long mode; 655 | PspellConfig *config; 656 | 657 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &zcfg, php_pspell_config_ce, &mode) == FAILURE) { 658 | RETURN_THROWS(); 659 | } 660 | config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg; 661 | 662 | /* First check what mode we want (how many suggestions) */ 663 | if (mode == PSPELL_FAST) { 664 | pspell_config_replace(config, "sug-mode", "fast"); 665 | } else if (mode == PSPELL_NORMAL) { 666 | pspell_config_replace(config, "sug-mode", "normal"); 667 | } else if (mode == PSPELL_BAD_SPELLERS) { 668 | pspell_config_replace(config, "sug-mode", "bad-spellers"); 669 | } 670 | 671 | RETURN_TRUE; 672 | } 673 | /* }}} */ 674 | 675 | /* {{{ Ignore words <= n chars */ 676 | PHP_FUNCTION(pspell_config_ignore) 677 | { 678 | char ignore_str[MAX_LENGTH_OF_LONG + 1]; 679 | zval *zcfg; 680 | zend_long ignore = 0L; 681 | PspellConfig *config; 682 | 683 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &zcfg, php_pspell_config_ce, &ignore) == FAILURE) { 684 | RETURN_THROWS(); 685 | } 686 | config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg; 687 | 688 | snprintf(ignore_str, sizeof(ignore_str), ZEND_LONG_FMT, ignore); 689 | 690 | pspell_config_replace(config, "ignore", ignore_str); 691 | RETURN_TRUE; 692 | } 693 | /* }}} */ 694 | 695 | static void pspell_config_path(INTERNAL_FUNCTION_PARAMETERS, char *option) 696 | { 697 | zval *zcfg; 698 | zend_string *value; 699 | PspellConfig *config; 700 | 701 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "OP", &zcfg, php_pspell_config_ce, &value) == FAILURE) { 702 | RETURN_THROWS(); 703 | } 704 | config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg; 705 | 706 | if (php_check_open_basedir(ZSTR_VAL(value))) { 707 | RETURN_FALSE; 708 | } 709 | 710 | pspell_config_replace(config, option, ZSTR_VAL(value)); 711 | 712 | RETURN_TRUE; 713 | } 714 | 715 | /* {{{ Use a personal dictionary for this config */ 716 | PHP_FUNCTION(pspell_config_personal) 717 | { 718 | pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "personal"); 719 | } 720 | /* }}} */ 721 | 722 | /* {{{ location of the main word list */ 723 | PHP_FUNCTION(pspell_config_dict_dir) 724 | { 725 | pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "dict-dir"); 726 | } 727 | /* }}} */ 728 | 729 | /* {{{ location of language data files */ 730 | PHP_FUNCTION(pspell_config_data_dir) 731 | { 732 | pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "data-dir"); 733 | } 734 | /* }}} */ 735 | 736 | /* {{{ Use a personal dictionary with replacement pairs for this config */ 737 | PHP_FUNCTION(pspell_config_repl) 738 | { 739 | zval *zcfg; 740 | zend_string *repl; 741 | PspellConfig *config; 742 | 743 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "OP", &zcfg, php_pspell_config_ce, &repl) == FAILURE) { 744 | RETURN_THROWS(); 745 | } 746 | config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg; 747 | 748 | pspell_config_replace(config, "save-repl", "true"); 749 | 750 | if (php_check_open_basedir(ZSTR_VAL(repl))) { 751 | RETURN_FALSE; 752 | } 753 | 754 | pspell_config_replace(config, "repl", ZSTR_VAL(repl)); 755 | 756 | RETURN_TRUE; 757 | } 758 | /* }}} */ 759 | 760 | /* {{{ Save replacement pairs when personal list is saved for this config */ 761 | PHP_FUNCTION(pspell_config_save_repl) 762 | { 763 | zval *zcfg; 764 | bool save; 765 | PspellConfig *config; 766 | 767 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ob", &zcfg, php_pspell_config_ce, &save) == FAILURE) { 768 | RETURN_THROWS(); 769 | } 770 | config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg; 771 | 772 | pspell_config_replace(config, "save-repl", save ? "true" : "false"); 773 | 774 | RETURN_TRUE; 775 | } 776 | /* }}} */ 777 | 778 | /* {{{ PHP_MINFO_FUNCTION */ 779 | static PHP_MINFO_FUNCTION(pspell) 780 | { 781 | php_info_print_table_start(); 782 | php_info_print_table_row(2, "PSpell Support", "enabled"); 783 | php_info_print_table_row(2, "PSpell extension version", PHP_PSPELL_VERSION); 784 | php_info_print_table_end(); 785 | } 786 | /* }}} */ 787 | 788 | #endif 789 | --------------------------------------------------------------------------------