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