1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 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 272370 2008-12-31 11:15:49Z sebastian $ */
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 : {NULL, NULL, NULL}
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 13 : {
218 13 : PspellManager *manager = (PspellManager *)rsrc->ptr;
219 :
220 13 : delete_pspell_manager(manager);
221 13 : }
222 :
223 : static void php_pspell_close_config(zend_rsrc_list_entry *rsrc TSRMLS_DC)
224 4 : {
225 4 : PspellConfig *config = (PspellConfig *)rsrc->ptr;
226 :
227 4 : delete_pspell_config(config);
228 4 : }
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 17633 : {
248 17633 : REGISTER_LONG_CONSTANT("PSPELL_FAST", PSPELL_FAST, CONST_PERSISTENT | CONST_CS);
249 17633 : REGISTER_LONG_CONSTANT("PSPELL_NORMAL", PSPELL_NORMAL, CONST_PERSISTENT | CONST_CS);
250 17633 : REGISTER_LONG_CONSTANT("PSPELL_BAD_SPELLERS", PSPELL_BAD_SPELLERS, CONST_PERSISTENT | CONST_CS);
251 17633 : REGISTER_LONG_CONSTANT("PSPELL_RUN_TOGETHER", PSPELL_RUN_TOGETHER, CONST_PERSISTENT | CONST_CS);
252 17633 : le_pspell = zend_register_list_destructors_ex(php_pspell_close, NULL, "pspell", module_number);
253 17633 : le_pspell_config = zend_register_list_destructors_ex(php_pspell_close_config, NULL, "pspell config", module_number);
254 17633 : 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 7 : {
262 7 : char *language, *spelling = NULL, *jargon = NULL, *encoding = NULL;
263 7 : int language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0;
264 7 : long mode = 0L, speed = 0L;
265 7 : 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 7 : 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 0 : return;
283 : }
284 :
285 7 : 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 7 : pspell_config_replace(config, "language-tag", language);
309 :
310 7 : if (spelling_len) {
311 0 : pspell_config_replace(config, "spelling", spelling);
312 : }
313 :
314 7 : if (jargon_len) {
315 0 : pspell_config_replace(config, "jargon", jargon);
316 : }
317 :
318 7 : if (encoding_len) {
319 0 : pspell_config_replace(config, "encoding", encoding);
320 : }
321 :
322 7 : if (argc > 4) {
323 2 : speed = mode & PSPELL_SPEED_MASK_INTERNAL;
324 :
325 : /* First check what mode we want (how many suggestions) */
326 2 : if (speed == PSPELL_FAST) {
327 2 : pspell_config_replace(config, "sug-mode", "fast");
328 0 : } else if (speed == PSPELL_NORMAL) {
329 0 : pspell_config_replace(config, "sug-mode", "normal");
330 0 : } else if (speed == PSPELL_BAD_SPELLERS) {
331 0 : 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 2 : if (mode & PSPELL_RUN_TOGETHER) {
336 2 : pspell_config_replace(config, "run-together", "true");
337 : }
338 : }
339 :
340 7 : ret = new_pspell_manager(config);
341 7 : delete_pspell_config(config);
342 :
343 7 : if (pspell_error_number(ret) != 0) {
344 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret));
345 0 : delete_pspell_can_have_error(ret);
346 0 : RETURN_FALSE;
347 : }
348 :
349 7 : manager = to_pspell_manager(ret);
350 7 : ind = zend_list_insert(manager, le_pspell);
351 7 : 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 2 : {
359 2 : char *personal, *language, *spelling = NULL, *jargon = NULL, *encoding = NULL;
360 2 : int personal_len, language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0;
361 2 : long mode = 0L, speed = 0L;
362 2 : 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 2 : 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 0 : return;
380 : }
381 :
382 2 : 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 2 : if (PG(safe_mode) && (!php_checkuid(personal, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
406 0 : delete_pspell_config(config);
407 0 : RETURN_FALSE;
408 : }
409 :
410 2 : if (php_check_open_basedir(personal TSRMLS_CC)) {
411 0 : delete_pspell_config(config);
412 0 : RETURN_FALSE;
413 : }
414 :
415 2 : pspell_config_replace(config, "personal", personal);
416 2 : pspell_config_replace(config, "save-repl", "false");
417 :
418 2 : pspell_config_replace(config, "language-tag", language);
419 :
420 2 : if (spelling_len) {
421 0 : pspell_config_replace(config, "spelling", spelling);
422 : }
423 :
424 2 : if (jargon_len) {
425 0 : pspell_config_replace(config, "jargon", jargon);
426 : }
427 :
428 2 : if (encoding_len) {
429 0 : pspell_config_replace(config, "encoding", encoding);
430 : }
431 :
432 2 : if (argc > 5) {
433 0 : speed = mode & PSPELL_SPEED_MASK_INTERNAL;
434 :
435 : /* First check what mode we want (how many suggestions) */
436 0 : if (speed == PSPELL_FAST) {
437 0 : pspell_config_replace(config, "sug-mode", "fast");
438 0 : } else if (speed == PSPELL_NORMAL) {
439 0 : pspell_config_replace(config, "sug-mode", "normal");
440 0 : } else if (speed == PSPELL_BAD_SPELLERS) {
441 0 : pspell_config_replace(config, "sug-mode", "bad-spellers");
442 : }
443 :
444 : /* Then we see if run-together words should be treated as valid components */
445 0 : if (mode & PSPELL_RUN_TOGETHER) {
446 0 : pspell_config_replace(config, "run-together", "true");
447 : }
448 : }
449 :
450 2 : ret = new_pspell_manager(config);
451 2 : delete_pspell_config(config);
452 :
453 2 : if (pspell_error_number(ret) != 0) {
454 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret));
455 1 : delete_pspell_can_have_error(ret);
456 1 : RETURN_FALSE;
457 : }
458 :
459 1 : manager = to_pspell_manager(ret);
460 1 : ind = zend_list_insert(manager, le_pspell);
461 1 : RETURN_LONG(ind);
462 : }
463 : /* }}} */
464 :
465 : /* {{{ proto int pspell_new_config(int config)
466 : Load a dictionary based on the given config */
467 : static PHP_FUNCTION(pspell_new_config)
468 6 : {
469 : int type, ind;
470 : long conf;
471 : PspellCanHaveError *ret;
472 : PspellManager *manager;
473 : PspellConfig *config;
474 :
475 6 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &conf) == FAILURE) {
476 0 : return;
477 : }
478 :
479 6 : PSPELL_FETCH_CONFIG;
480 :
481 6 : ret = new_pspell_manager(config);
482 :
483 6 : if (pspell_error_number(ret) != 0) {
484 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret));
485 1 : delete_pspell_can_have_error(ret);
486 1 : RETURN_FALSE;
487 : }
488 :
489 5 : manager = to_pspell_manager(ret);
490 5 : ind = zend_list_insert(manager, le_pspell);
491 5 : RETURN_LONG(ind);
492 : }
493 : /* }}} */
494 :
495 : /* {{{ proto bool pspell_check(int pspell, string word)
496 : Returns true if word is valid */
497 : static PHP_FUNCTION(pspell_check)
498 88 : {
499 : int type, word_len;
500 : long scin;
501 : char *word;
502 : PspellManager *manager;
503 :
504 88 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &scin, &word, &word_len) == FAILURE) {
505 1 : return;
506 : }
507 :
508 87 : PSPELL_FETCH_MANAGER;
509 :
510 86 : if (pspell_manager_check(manager, word)) {
511 79 : RETURN_TRUE;
512 : } else {
513 7 : RETURN_FALSE;
514 : }
515 : }
516 : /* }}} */
517 :
518 : /* {{{ proto array pspell_suggest(int pspell, string word)
519 : Returns array of suggestions */
520 : static PHP_FUNCTION(pspell_suggest)
521 2 : {
522 : long scin;
523 : char *word;
524 : int word_len;
525 : PspellManager *manager;
526 : int type;
527 : const PspellWordList *wl;
528 : const char *sug;
529 :
530 2 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &scin, &word, &word_len) == FAILURE) {
531 0 : return;
532 : }
533 :
534 2 : PSPELL_FETCH_MANAGER;
535 :
536 2 : array_init(return_value);
537 :
538 2 : wl = pspell_manager_suggest(manager, word);
539 2 : if (wl) {
540 2 : PspellStringEmulation *els = pspell_word_list_elements(wl);
541 49 : while ((sug = pspell_string_emulation_next(els)) != 0) {
542 45 : add_next_index_string(return_value,(char *)sug,1);
543 : }
544 2 : delete_pspell_string_emulation(els);
545 : } else {
546 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "PSPELL had a problem. details: %s", pspell_manager_error_message(manager));
547 0 : RETURN_FALSE;
548 : }
549 : }
550 : /* }}} */
551 :
552 : /* {{{ proto bool pspell_store_replacement(int pspell, string misspell, string correct)
553 : Notify the dictionary of a user-selected replacement */
554 : static PHP_FUNCTION(pspell_store_replacement)
555 0 : {
556 : int type, miss_len, corr_len;
557 : long scin;
558 : char *miss, *corr;
559 : PspellManager *manager;
560 :
561 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lss", &scin, &miss, &miss_len, &corr, &corr_len) == FAILURE) {
562 0 : return;
563 : }
564 :
565 0 : PSPELL_FETCH_MANAGER;
566 :
567 0 : pspell_manager_store_replacement(manager, miss, corr);
568 0 : if (pspell_manager_error_number(manager) == 0) {
569 0 : RETURN_TRUE;
570 : } else {
571 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "pspell_store_replacement() gave error: %s", pspell_manager_error_message(manager));
572 0 : RETURN_FALSE;
573 : }
574 : }
575 : /* }}} */
576 :
577 : /* {{{ proto bool pspell_add_to_personal(int pspell, string word)
578 : Adds a word to a personal list */
579 : static PHP_FUNCTION(pspell_add_to_personal)
580 1 : {
581 : int type, word_len;
582 : long scin;
583 : char *word;
584 : PspellManager *manager;
585 :
586 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &scin, &word, &word_len) == FAILURE) {
587 0 : return;
588 : }
589 :
590 1 : PSPELL_FETCH_MANAGER;
591 :
592 : /*If the word is empty, we have to return; otherwise we'll segfault! ouch!*/
593 1 : if (word_len == 0) {
594 0 : RETURN_FALSE;
595 : }
596 :
597 1 : pspell_manager_add_to_personal(manager, word);
598 1 : if (pspell_manager_error_number(manager) == 0) {
599 1 : RETURN_TRUE;
600 : } else {
601 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "pspell_add_to_personal() gave error: %s", pspell_manager_error_message(manager));
602 0 : RETURN_FALSE;
603 : }
604 : }
605 : /* }}} */
606 :
607 : /* {{{ proto bool pspell_add_to_session(int pspell, string word)
608 : Adds a word to the current session */
609 : static PHP_FUNCTION(pspell_add_to_session)
610 2 : {
611 : int type, word_len;
612 : long scin;
613 : char *word;
614 : PspellManager *manager;
615 :
616 2 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &scin, &word, &word_len) == FAILURE) {
617 0 : return;
618 : }
619 :
620 2 : PSPELL_FETCH_MANAGER;
621 :
622 : /*If the word is empty, we have to return; otherwise we'll segfault! ouch!*/
623 2 : if (word_len == 0) {
624 1 : RETURN_FALSE;
625 : }
626 :
627 1 : pspell_manager_add_to_session(manager, word);
628 1 : if (pspell_manager_error_number(manager) == 0) {
629 1 : RETURN_TRUE;
630 : } else {
631 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "pspell_add_to_session() gave error: %s", pspell_manager_error_message(manager));
632 0 : RETURN_FALSE;
633 : }
634 : }
635 : /* }}} */
636 :
637 : /* {{{ proto bool pspell_clear_session(int pspell)
638 : Clears the current session */
639 : static PHP_FUNCTION(pspell_clear_session)
640 2 : {
641 : int type;
642 : long scin;
643 : PspellManager *manager;
644 :
645 2 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &scin) == FAILURE) {
646 1 : return;
647 : }
648 :
649 1 : PSPELL_FETCH_MANAGER;
650 :
651 1 : pspell_manager_clear_session(manager);
652 1 : if (pspell_manager_error_number(manager) == 0) {
653 1 : RETURN_TRUE;
654 : } else {
655 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "pspell_clear_session() gave error: %s", pspell_manager_error_message(manager));
656 0 : RETURN_FALSE;
657 : }
658 : }
659 : /* }}} */
660 :
661 : /* {{{ proto bool pspell_save_wordlist(int pspell)
662 : Saves the current (personal) wordlist */
663 : static PHP_FUNCTION(pspell_save_wordlist)
664 1 : {
665 : int type;
666 : long scin;
667 : PspellManager *manager;
668 :
669 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &scin) == FAILURE) {
670 0 : return;
671 : }
672 :
673 1 : PSPELL_FETCH_MANAGER;
674 :
675 1 : pspell_manager_save_all_word_lists(manager);
676 :
677 1 : if (pspell_manager_error_number(manager) == 0) {
678 1 : RETURN_TRUE;
679 : } else {
680 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "pspell_save_wordlist() gave error: %s", pspell_manager_error_message(manager));
681 0 : RETURN_FALSE;
682 : }
683 :
684 : }
685 : /* }}} */
686 :
687 : /* {{{ proto int pspell_config_create(string language [, string spelling [, string jargon [, string encoding]]])
688 : Create a new config to be used later to create a manager */
689 : static PHP_FUNCTION(pspell_config_create)
690 4 : {
691 4 : char *language, *spelling = NULL, *jargon = NULL, *encoding = NULL;
692 4 : int language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0;
693 : int ind;
694 : PspellConfig *config;
695 :
696 : #ifdef PHP_WIN32
697 : TCHAR aspell_dir[200];
698 : TCHAR data_dir[220];
699 : TCHAR dict_dir[220];
700 : HKEY hkey;
701 : DWORD dwType,dwLen;
702 : #endif
703 :
704 4 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sss", &language, &language_len, &spelling, &spelling_len,
705 : &jargon, &jargon_len, &encoding, &encoding_len) == FAILURE) {
706 0 : return;
707 : }
708 :
709 4 : config = new_pspell_config();
710 :
711 : #ifdef PHP_WIN32
712 : /* If aspell was installed using installer, we should have a key
713 : * pointing to the location of the dictionaries
714 : */
715 : if (0 == RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Aspell", &hkey)) {
716 : LONG result;
717 : dwLen = sizeof(aspell_dir) - 1;
718 : result = RegQueryValueEx(hkey, "", NULL, &dwType, (LPBYTE)&aspell_dir, &dwLen);
719 : RegCloseKey(hkey);
720 : if (result == ERROR_SUCCESS) {
721 : strlcpy(data_dir, aspell_dir, sizeof(data_dir));
722 : strlcat(data_dir, "\\data", sizeof(data_dir));
723 : strlcpy(dict_dir, aspell_dir, sizeof(dict_dir));
724 : strlcat(dict_dir, "\\dict", sizeof(dict_dir));
725 :
726 : pspell_config_replace(config, "data-dir", data_dir);
727 : pspell_config_replace(config, "dict-dir", dict_dir);
728 : }
729 : }
730 : #endif
731 :
732 4 : pspell_config_replace(config, "language-tag", language);
733 :
734 4 : if (spelling_len) {
735 3 : pspell_config_replace(config, "spelling", spelling);
736 : }
737 :
738 4 : if (jargon_len) {
739 0 : pspell_config_replace(config, "jargon", jargon);
740 : }
741 :
742 4 : if (encoding_len) {
743 3 : pspell_config_replace(config, "encoding", encoding);
744 : }
745 :
746 : /* By default I do not want to write anything anywhere because it'll try to write to $HOME
747 : which is not what we want */
748 4 : pspell_config_replace(config, "save-repl", "false");
749 :
750 4 : ind = zend_list_insert(config, le_pspell_config);
751 4 : RETURN_LONG(ind);
752 : }
753 : /* }}} */
754 :
755 : /* {{{ proto bool pspell_config_runtogether(int conf, bool runtogether)
756 : Consider run-together words as valid components */
757 : static PHP_FUNCTION(pspell_config_runtogether)
758 3 : {
759 : int type;
760 : long conf;
761 : zend_bool runtogether;
762 : PspellConfig *config;
763 :
764 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lb", &conf, &runtogether) == FAILURE) {
765 0 : return;
766 : }
767 :
768 3 : PSPELL_FETCH_CONFIG;
769 :
770 3 : pspell_config_replace(config, "run-together", runtogether ? "true" : "false");
771 :
772 3 : RETURN_TRUE;
773 : }
774 : /* }}} */
775 :
776 : /* {{{ proto bool pspell_config_mode(int conf, long mode)
777 : Select mode for config (PSPELL_FAST, PSPELL_NORMAL or PSPELL_BAD_SPELLERS) */
778 : static PHP_FUNCTION(pspell_config_mode)
779 1 : {
780 : int type;
781 : long conf, mode;
782 : PspellConfig *config;
783 :
784 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &conf, &mode) == FAILURE) {
785 0 : return;
786 : }
787 :
788 1 : PSPELL_FETCH_CONFIG;
789 :
790 : /* First check what mode we want (how many suggestions) */
791 1 : if (mode == PSPELL_FAST) {
792 0 : pspell_config_replace(config, "sug-mode", "fast");
793 1 : } else if (mode == PSPELL_NORMAL) {
794 0 : pspell_config_replace(config, "sug-mode", "normal");
795 1 : } else if (mode == PSPELL_BAD_SPELLERS) {
796 1 : pspell_config_replace(config, "sug-mode", "bad-spellers");
797 : }
798 :
799 1 : RETURN_TRUE;
800 : }
801 : /* }}} */
802 :
803 : /* {{{ proto bool pspell_config_ignore(int conf, int ignore)
804 : Ignore words <= n chars */
805 : static PHP_FUNCTION(pspell_config_ignore)
806 2 : {
807 : int type;
808 : char ignore_str[MAX_LENGTH_OF_LONG + 1];
809 2 : long conf, ignore = 0L;
810 : PspellConfig *config;
811 :
812 2 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &conf, &ignore) == FAILURE) {
813 0 : return;
814 : }
815 :
816 2 : PSPELL_FETCH_CONFIG;
817 :
818 2 : snprintf(ignore_str, sizeof(ignore_str), "%ld", ignore);
819 :
820 2 : pspell_config_replace(config, "ignore", ignore_str);
821 2 : RETURN_TRUE;
822 : }
823 : /* }}} */
824 :
825 : static void pspell_config_path(INTERNAL_FUNCTION_PARAMETERS, char *option)
826 1 : {
827 : int type;
828 : long conf;
829 : char *value;
830 : int value_len;
831 : PspellConfig *config;
832 :
833 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &conf, &value, &value_len) == FAILURE) {
834 0 : return;
835 : }
836 :
837 1 : PSPELL_FETCH_CONFIG;
838 :
839 1 : if (PG(safe_mode) && (!php_checkuid(value, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
840 0 : RETURN_FALSE;
841 : }
842 :
843 1 : if (php_check_open_basedir(value TSRMLS_CC)) {
844 0 : RETURN_FALSE;
845 : }
846 :
847 1 : pspell_config_replace(config, option, value);
848 :
849 1 : RETURN_TRUE;
850 : }
851 :
852 : /* {{{ proto bool pspell_config_personal(int conf, string personal)
853 : Use a personal dictionary for this config */
854 : static PHP_FUNCTION(pspell_config_personal)
855 1 : {
856 1 : pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "personal");
857 1 : }
858 : /* }}} */
859 :
860 : /* {{{ proto bool pspell_config_dict_dir(int conf, string directory)
861 : location of the main word list */
862 : static PHP_FUNCTION(pspell_config_dict_dir)
863 0 : {
864 0 : pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "dict-dir");
865 0 : }
866 : /* }}} */
867 :
868 : /* {{{ proto bool pspell_config_data_dir(int conf, string directory)
869 : location of language data files */
870 : static PHP_FUNCTION(pspell_config_data_dir)
871 0 : {
872 0 : pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "data-dir");
873 0 : }
874 : /* }}} */
875 :
876 : /* {{{ proto bool pspell_config_repl(int conf, string repl)
877 : Use a personal dictionary with replacement pairs for this config */
878 : static PHP_FUNCTION(pspell_config_repl)
879 0 : {
880 : int type;
881 : long conf;
882 : char *repl;
883 : int repl_len;
884 : PspellConfig *config;
885 :
886 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &conf, &repl, &repl_len) == FAILURE) {
887 0 : return;
888 : }
889 :
890 0 : PSPELL_FETCH_CONFIG;
891 :
892 0 : pspell_config_replace(config, "save-repl", "true");
893 :
894 0 : if (PG(safe_mode) && (!php_checkuid(repl, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
895 0 : RETURN_FALSE;
896 : }
897 :
898 0 : if (php_check_open_basedir(repl TSRMLS_CC)) {
899 0 : RETURN_FALSE;
900 : }
901 :
902 0 : pspell_config_replace(config, "repl", repl);
903 :
904 0 : RETURN_TRUE;
905 : }
906 : /* }}} */
907 :
908 : /* {{{ proto bool pspell_config_save_repl(int conf, bool save)
909 : Save replacement pairs when personal list is saved for this config */
910 : static PHP_FUNCTION(pspell_config_save_repl)
911 0 : {
912 : int type;
913 : long conf;
914 : zend_bool save;
915 : PspellConfig *config;
916 :
917 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lb", &conf, &save) == FAILURE) {
918 0 : return;
919 : }
920 :
921 0 : PSPELL_FETCH_CONFIG;
922 :
923 0 : pspell_config_replace(config, "save-repl", save ? "true" : "false");
924 :
925 0 : RETURN_TRUE;
926 : }
927 : /* }}} */
928 :
929 : /* {{{ PHP_MINFO_FUNCTION
930 : */
931 : static PHP_MINFO_FUNCTION(pspell)
932 42 : {
933 42 : php_info_print_table_start();
934 42 : php_info_print_table_row(2, "PSpell Support", "enabled");
935 42 : php_info_print_table_end();
936 42 : }
937 : /* }}} */
938 :
939 : #endif
940 :
941 : /*
942 : * Local variables:
943 : * tab-width: 4
944 : * c-basic-offset: 4
945 : * End:
946 : * vim600: sw=4 ts=4 fdm=marker
947 : * vim<600: sw=4 ts=4
948 : */
|