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 <phpdevel@echospace.com> |
14 +----------------------------------------------------------------------+
15 */
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include "php.h"
22
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include <stdio.h>
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 <pspell.h>
34 #include "ext/standard/info.h"
35 #include "pspell_arginfo.h"
36
37 #define PSPELL_FAST 1L
38 #define PSPELL_NORMAL 2L
39 #define PSPELL_BAD_SPELLERS 3L
40 #define PSPELL_SPEED_MASK_INTERNAL 3L
41 #define PSPELL_RUN_TOGETHER 8L
42
43 /* Largest ignored word can be 999 characters (this seems sane enough),
44 * and it takes 3 bytes to represent that (see pspell_config_ignore)
45 */
46 #define PSPELL_LARGEST_WORD 3
47
48 static PHP_MINIT_FUNCTION(pspell);
49 static PHP_MINFO_FUNCTION(pspell);
50
51 static zend_class_entry *php_pspell_ce = NULL;
52 static zend_object_handlers php_pspell_handlers;
53 static zend_class_entry *php_pspell_config_ce = NULL;
54 static zend_object_handlers php_pspell_config_handlers;
55
56 zend_module_entry pspell_module_entry = {
57 STANDARD_MODULE_HEADER,
58 "pspell",
59 ext_functions,
60 PHP_MINIT(pspell),
61 NULL,
62 NULL,
63 NULL,
64 PHP_MINFO(pspell),
65 PHP_PSPELL_VERSION,
66 STANDARD_MODULE_PROPERTIES,
67 };
68
69 #ifdef COMPILE_DL_PSPELL
70 ZEND_GET_MODULE(pspell)
71 #endif
72
73 /* class PSpell */
74
75 typedef struct _php_pspell_object {
76 PspellManager *mgr;
77 zend_object std;
78 } php_pspell_object;
79
php_pspell_object_from_zend_object(zend_object * zobj)80 static php_pspell_object *php_pspell_object_from_zend_object(zend_object *zobj) {
81 return ((php_pspell_object*)(zobj + 1)) - 1;
82 }
83
php_pspell_object_to_zend_object(php_pspell_object * obj)84 static zend_object *php_pspell_object_to_zend_object(php_pspell_object *obj) {
85 return ((zend_object*)(obj + 1)) - 1;
86 }
87
php_pspell_object_get_constructor(zend_object * object)88 static zend_function *php_pspell_object_get_constructor(zend_object *object)
89 {
90 zend_throw_error(NULL, "You cannot initialize a PSpell\\Dictionary object except through helper functions");
91 return NULL;
92 }
93
php_pspell_object_create(zend_class_entry * ce)94 static zend_object *php_pspell_object_create(zend_class_entry *ce)
95 {
96 php_pspell_object *obj = zend_object_alloc(sizeof(php_pspell_object), ce);
97 zend_object *zobj = php_pspell_object_to_zend_object(obj);
98
99 obj->mgr = NULL;
100 zend_object_std_init(zobj, ce);
101 object_properties_init(zobj, ce);
102 zobj->handlers = &php_pspell_handlers;
103
104 return zobj;
105 }
106
php_pspell_object_free(zend_object * zobj)107 static void php_pspell_object_free(zend_object *zobj) {
108 delete_pspell_manager(php_pspell_object_from_zend_object(zobj)->mgr);
109 }
110
111 /* class PSpellConfig */
112
113 typedef struct _php_pspell_config_object {
114 PspellConfig *cfg;
115 zend_object std;
116 } php_pspell_config_object;
117
php_pspell_config_object_from_zend_object(zend_object * zobj)118 static php_pspell_config_object *php_pspell_config_object_from_zend_object(zend_object *zobj) {
119 return ((php_pspell_config_object*)(zobj + 1)) - 1;
120 }
121
php_pspell_config_object_to_zend_object(php_pspell_config_object * obj)122 static zend_object *php_pspell_config_object_to_zend_object(php_pspell_config_object *obj) {
123 return ((zend_object*)(obj + 1)) - 1;
124 }
125
php_pspell_config_object_get_constructor(zend_object * object)126 static zend_function *php_pspell_config_object_get_constructor(zend_object *object)
127 {
128 zend_throw_error(NULL, "You cannot initialize a PSpell\\Config object except through helper functions");
129 return NULL;
130 }
131
php_pspell_config_object_create(zend_class_entry * ce)132 static zend_object *php_pspell_config_object_create(zend_class_entry *ce)
133 {
134 php_pspell_config_object *obj = zend_object_alloc(sizeof(php_pspell_config_object), ce);
135 zend_object *zobj = php_pspell_config_object_to_zend_object(obj);
136
137 obj->cfg = NULL;
138 zend_object_std_init(zobj, ce);
139 object_properties_init(zobj, ce);
140 zobj->handlers = &php_pspell_config_handlers;
141
142 return zobj;
143 }
144
php_pspell_config_object_free(zend_object * zobj)145 static void php_pspell_config_object_free(zend_object *zobj) {
146 delete_pspell_config(php_pspell_config_object_from_zend_object(zobj)->cfg);
147 }
148
149 /* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(pspell)150 static PHP_MINIT_FUNCTION(pspell)
151 {
152 php_pspell_ce = register_class_PSpell_Dictionary();
153 php_pspell_ce->create_object = php_pspell_object_create;
154
155 memcpy(&php_pspell_handlers, &std_object_handlers, sizeof(zend_object_handlers));
156 php_pspell_handlers.clone_obj = NULL;
157 php_pspell_handlers.free_obj = php_pspell_object_free;
158 php_pspell_handlers.get_constructor = php_pspell_object_get_constructor;
159 php_pspell_handlers.offset = XtOffsetOf(php_pspell_object, std);
160
161 php_pspell_config_ce = register_class_PSpell_Config();
162 php_pspell_config_ce->create_object = php_pspell_config_object_create;
163
164 memcpy(&php_pspell_config_handlers, &std_object_handlers, sizeof(zend_object_handlers));
165 php_pspell_config_handlers.clone_obj = NULL;
166 php_pspell_config_handlers.free_obj = php_pspell_config_object_free;
167 php_pspell_config_handlers.get_constructor = php_pspell_config_object_get_constructor;
168 php_pspell_config_handlers.offset = XtOffsetOf(php_pspell_config_object, std);
169
170 REGISTER_LONG_CONSTANT("PSPELL_FAST", PSPELL_FAST, CONST_PERSISTENT | CONST_CS);
171 REGISTER_LONG_CONSTANT("PSPELL_NORMAL", PSPELL_NORMAL, CONST_PERSISTENT | CONST_CS);
172 REGISTER_LONG_CONSTANT("PSPELL_BAD_SPELLERS", PSPELL_BAD_SPELLERS, CONST_PERSISTENT | CONST_CS);
173 REGISTER_LONG_CONSTANT("PSPELL_RUN_TOGETHER", PSPELL_RUN_TOGETHER, CONST_PERSISTENT | CONST_CS);
174
175 return SUCCESS;
176 }
177 /* }}} */
178
179 /* {{{ Load a dictionary */
PHP_FUNCTION(pspell_new)180 PHP_FUNCTION(pspell_new)
181 {
182 char *language, *spelling = NULL, *jargon = NULL, *encoding = NULL;
183 size_t language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0;
184 zend_long mode = Z_L(0), speed = Z_L(0);
185 int argc = ZEND_NUM_ARGS();
186
187 #ifdef PHP_WIN32
188 TCHAR aspell_dir[200];
189 TCHAR data_dir[220];
190 TCHAR dict_dir[220];
191 HKEY hkey;
192 DWORD dwType,dwLen;
193 #endif
194
195 PspellCanHaveError *ret;
196 PspellConfig *config;
197
198 if (zend_parse_parameters(argc, "s|sssl", &language, &language_len, &spelling, &spelling_len,
199 &jargon, &jargon_len, &encoding, &encoding_len, &mode) == FAILURE) {
200 RETURN_THROWS();
201 }
202
203 config = new_pspell_config();
204
205 #ifdef PHP_WIN32
206 /* If aspell was installed using installer, we should have a key
207 * pointing to the location of the dictionaries
208 */
209 if (0 == RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Aspell", &hkey)) {
210 LONG result;
211 dwLen = sizeof(aspell_dir) - 1;
212 result = RegQueryValueEx(hkey, "", NULL, &dwType, (LPBYTE)&aspell_dir, &dwLen);
213 RegCloseKey(hkey);
214 if (result == ERROR_SUCCESS) {
215 strlcpy(data_dir, aspell_dir, sizeof(data_dir));
216 strlcat(data_dir, "\\data", sizeof(data_dir));
217 strlcpy(dict_dir, aspell_dir, sizeof(dict_dir));
218 strlcat(dict_dir, "\\dict", sizeof(dict_dir));
219
220 pspell_config_replace(config, "data-dir", data_dir);
221 pspell_config_replace(config, "dict-dir", dict_dir);
222 }
223 }
224 #endif
225
226 pspell_config_replace(config, "language-tag", language);
227
228 if (spelling_len) {
229 pspell_config_replace(config, "spelling", spelling);
230 }
231
232 if (jargon_len) {
233 pspell_config_replace(config, "jargon", jargon);
234 }
235
236 if (encoding_len) {
237 pspell_config_replace(config, "encoding", encoding);
238 }
239
240 if (mode) {
241 speed = mode & PSPELL_SPEED_MASK_INTERNAL;
242
243 /* First check what mode we want (how many suggestions) */
244 if (speed == PSPELL_FAST) {
245 pspell_config_replace(config, "sug-mode", "fast");
246 } else if (speed == PSPELL_NORMAL) {
247 pspell_config_replace(config, "sug-mode", "normal");
248 } else if (speed == PSPELL_BAD_SPELLERS) {
249 pspell_config_replace(config, "sug-mode", "bad-spellers");
250 }
251
252 /* Then we see if run-together words should be treated as valid components */
253 if (mode & PSPELL_RUN_TOGETHER) {
254 pspell_config_replace(config, "run-together", "true");
255 }
256 }
257
258 ret = new_pspell_manager(config);
259 delete_pspell_config(config);
260
261 if (pspell_error_number(ret) != 0) {
262 php_error_docref(NULL, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret));
263 delete_pspell_can_have_error(ret);
264 RETURN_FALSE;
265 }
266
267 object_init_ex(return_value, php_pspell_ce);
268 php_pspell_object_from_zend_object(Z_OBJ_P(return_value))->mgr = to_pspell_manager(ret);
269 }
270 /* }}} */
271
272 /* {{{ Load a dictionary with a personal wordlist*/
PHP_FUNCTION(pspell_new_personal)273 PHP_FUNCTION(pspell_new_personal)
274 {
275 char *personal, *language, *spelling = NULL, *jargon = NULL, *encoding = NULL;
276 size_t personal_len, language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0;
277 zend_long mode = Z_L(0), speed = Z_L(0);
278 int argc = ZEND_NUM_ARGS();
279
280 #ifdef PHP_WIN32
281 TCHAR aspell_dir[200];
282 TCHAR data_dir[220];
283 TCHAR dict_dir[220];
284 HKEY hkey;
285 DWORD dwType,dwLen;
286 #endif
287
288 PspellCanHaveError *ret;
289 PspellConfig *config;
290
291 if (zend_parse_parameters(argc, "ps|sssl", &personal, &personal_len, &language, &language_len,
292 &spelling, &spelling_len, &jargon, &jargon_len, &encoding, &encoding_len, &mode) == FAILURE) {
293 RETURN_THROWS();
294 }
295
296 config = new_pspell_config();
297
298 #ifdef PHP_WIN32
299 /* If aspell was installed using installer, we should have a key
300 * pointing to the location of the dictionaries
301 */
302 if (0 == RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Aspell", &hkey)) {
303 LONG result;
304 dwLen = sizeof(aspell_dir) - 1;
305 result = RegQueryValueEx(hkey, "", NULL, &dwType, (LPBYTE)&aspell_dir, &dwLen);
306 RegCloseKey(hkey);
307 if (result == ERROR_SUCCESS) {
308 strlcpy(data_dir, aspell_dir, sizeof(data_dir));
309 strlcat(data_dir, "\\data", sizeof(data_dir));
310 strlcpy(dict_dir, aspell_dir, sizeof(dict_dir));
311 strlcat(dict_dir, "\\dict", sizeof(dict_dir));
312
313 pspell_config_replace(config, "data-dir", data_dir);
314 pspell_config_replace(config, "dict-dir", dict_dir);
315 }
316 }
317 #endif
318
319 if (php_check_open_basedir(personal)) {
320 delete_pspell_config(config);
321 RETURN_FALSE;
322 }
323
324 pspell_config_replace(config, "personal", personal);
325 pspell_config_replace(config, "save-repl", "false");
326
327 pspell_config_replace(config, "language-tag", language);
328
329 if (spelling_len) {
330 pspell_config_replace(config, "spelling", spelling);
331 }
332
333 if (jargon_len) {
334 pspell_config_replace(config, "jargon", jargon);
335 }
336
337 if (encoding_len) {
338 pspell_config_replace(config, "encoding", encoding);
339 }
340
341 if (mode) {
342 speed = mode & PSPELL_SPEED_MASK_INTERNAL;
343
344 /* First check what mode we want (how many suggestions) */
345 if (speed == PSPELL_FAST) {
346 pspell_config_replace(config, "sug-mode", "fast");
347 } else if (speed == PSPELL_NORMAL) {
348 pspell_config_replace(config, "sug-mode", "normal");
349 } else if (speed == PSPELL_BAD_SPELLERS) {
350 pspell_config_replace(config, "sug-mode", "bad-spellers");
351 }
352
353 /* Then we see if run-together words should be treated as valid components */
354 if (mode & PSPELL_RUN_TOGETHER) {
355 pspell_config_replace(config, "run-together", "true");
356 }
357 }
358
359 ret = new_pspell_manager(config);
360 delete_pspell_config(config);
361
362 if (pspell_error_number(ret) != 0) {
363 php_error_docref(NULL, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret));
364 delete_pspell_can_have_error(ret);
365 RETURN_FALSE;
366 }
367
368 object_init_ex(return_value, php_pspell_ce);
369 php_pspell_object_from_zend_object(Z_OBJ_P(return_value))->mgr = to_pspell_manager(ret);
370 }
371 /* }}} */
372
373 /* {{{ Load a dictionary based on the given config */
PHP_FUNCTION(pspell_new_config)374 PHP_FUNCTION(pspell_new_config)
375 {
376 zval *zcfg;
377 PspellCanHaveError *ret;
378 PspellConfig *config;
379
380 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zcfg, php_pspell_config_ce) == FAILURE) {
381 RETURN_THROWS();
382 }
383 config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg;
384
385 ret = new_pspell_manager(config);
386
387 if (pspell_error_number(ret) != 0) {
388 php_error_docref(NULL, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret));
389 delete_pspell_can_have_error(ret);
390 RETURN_FALSE;
391 }
392
393 object_init_ex(return_value, php_pspell_ce);
394 php_pspell_object_from_zend_object(Z_OBJ_P(return_value))->mgr = to_pspell_manager(ret);
395 }
396 /* }}} */
397
398 /* {{{ Returns true if word is valid */
PHP_FUNCTION(pspell_check)399 PHP_FUNCTION(pspell_check)
400 {
401 zval *zmgr;
402 zend_string *word;
403 PspellManager *manager;
404
405 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS", &zmgr, php_pspell_ce, &word) == FAILURE) {
406 RETURN_THROWS();
407 }
408 manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr;
409
410 if (pspell_manager_check(manager, ZSTR_VAL(word))) {
411 RETURN_TRUE;
412 } else {
413 RETURN_FALSE;
414 }
415 }
416 /* }}} */
417
418 /* {{{ Returns array of suggestions */
PHP_FUNCTION(pspell_suggest)419 PHP_FUNCTION(pspell_suggest)
420 {
421 zval *zmgr;
422 zend_string *word;
423 PspellManager *manager;
424 const PspellWordList *wl;
425 const char *sug;
426
427 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS", &zmgr, php_pspell_ce, &word) == FAILURE) {
428 RETURN_THROWS();
429 }
430 manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr;
431
432 array_init(return_value);
433
434 wl = pspell_manager_suggest(manager, ZSTR_VAL(word));
435 if (wl) {
436 PspellStringEmulation *els = pspell_word_list_elements(wl);
437 while ((sug = pspell_string_emulation_next(els)) != 0) {
438 add_next_index_string(return_value,(char *)sug);
439 }
440 delete_pspell_string_emulation(els);
441 } else {
442 php_error_docref(NULL, E_WARNING, "PSPELL had a problem. details: %s", pspell_manager_error_message(manager));
443 RETURN_FALSE;
444 }
445 }
446 /* }}} */
447
448 /* {{{ Notify the dictionary of a user-selected replacement */
PHP_FUNCTION(pspell_store_replacement)449 PHP_FUNCTION(pspell_store_replacement)
450 {
451 zval *zmgr;
452 zend_string *miss, *corr;
453 PspellManager *manager;
454
455 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OSS", &zmgr, php_pspell_ce, &miss, &corr) == FAILURE) {
456 RETURN_THROWS();
457 }
458 manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr;
459
460 pspell_manager_store_replacement(manager, ZSTR_VAL(miss), ZSTR_VAL(corr));
461 if (pspell_manager_error_number(manager) == 0) {
462 RETURN_TRUE;
463 } else {
464 php_error_docref(NULL, E_WARNING, "pspell_store_replacement() gave error: %s", pspell_manager_error_message(manager));
465 RETURN_FALSE;
466 }
467 }
468 /* }}} */
469
470 /* {{{ Adds a word to a personal list */
PHP_FUNCTION(pspell_add_to_personal)471 PHP_FUNCTION(pspell_add_to_personal)
472 {
473 zval *zmgr;
474 zend_string *word;
475 PspellManager *manager;
476
477 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS", &zmgr, php_pspell_ce, &word) == FAILURE) {
478 RETURN_THROWS();
479 }
480 manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr;
481
482 /*If the word is empty, we have to return; otherwise we'll segfault! ouch!*/
483 if (ZSTR_LEN(word) == 0) {
484 RETURN_FALSE;
485 }
486
487 pspell_manager_add_to_personal(manager, ZSTR_VAL(word));
488 if (pspell_manager_error_number(manager) == 0) {
489 RETURN_TRUE;
490 } else {
491 php_error_docref(NULL, E_WARNING, "pspell_add_to_personal() gave error: %s", pspell_manager_error_message(manager));
492 RETURN_FALSE;
493 }
494 }
495 /* }}} */
496
497 /* {{{ Adds a word to the current session */
PHP_FUNCTION(pspell_add_to_session)498 PHP_FUNCTION(pspell_add_to_session)
499 {
500 zval *zmgr;
501 zend_string *word;
502 PspellManager *manager;
503
504 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS", &zmgr, php_pspell_ce, &word) == FAILURE) {
505 RETURN_THROWS();
506 }
507 manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr;
508
509 /*If the word is empty, we have to return; otherwise we'll segfault! ouch!*/
510 if (ZSTR_LEN(word) == 0) {
511 RETURN_FALSE;
512 }
513
514 pspell_manager_add_to_session(manager, ZSTR_VAL(word));
515 if (pspell_manager_error_number(manager) == 0) {
516 RETURN_TRUE;
517 } else {
518 php_error_docref(NULL, E_WARNING, "pspell_add_to_session() gave error: %s", pspell_manager_error_message(manager));
519 RETURN_FALSE;
520 }
521 }
522 /* }}} */
523
524 /* {{{ Clears the current session */
PHP_FUNCTION(pspell_clear_session)525 PHP_FUNCTION(pspell_clear_session)
526 {
527 zval *zmgr;
528 PspellManager *manager;
529
530 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zmgr, php_pspell_ce) == FAILURE) {
531 RETURN_THROWS();
532 }
533 manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr;
534
535 pspell_manager_clear_session(manager);
536 if (pspell_manager_error_number(manager) == 0) {
537 RETURN_TRUE;
538 } else {
539 php_error_docref(NULL, E_WARNING, "pspell_clear_session() gave error: %s", pspell_manager_error_message(manager));
540 RETURN_FALSE;
541 }
542 }
543 /* }}} */
544
545 /* {{{ Saves the current (personal) wordlist */
PHP_FUNCTION(pspell_save_wordlist)546 PHP_FUNCTION(pspell_save_wordlist)
547 {
548 zval *zmgr;
549 PspellManager *manager;
550
551 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zmgr, php_pspell_ce) == FAILURE) {
552 RETURN_THROWS();
553 }
554 manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr;
555
556 pspell_manager_save_all_word_lists(manager);
557
558 if (pspell_manager_error_number(manager) == 0) {
559 RETURN_TRUE;
560 } else {
561 php_error_docref(NULL, E_WARNING, "pspell_save_wordlist() gave error: %s", pspell_manager_error_message(manager));
562 RETURN_FALSE;
563 }
564
565 }
566 /* }}} */
567
568 /* {{{ Create a new config to be used later to create a manager */
PHP_FUNCTION(pspell_config_create)569 PHP_FUNCTION(pspell_config_create)
570 {
571 char *language, *spelling = NULL, *jargon = NULL, *encoding = NULL;
572 size_t language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0;
573 PspellConfig *config;
574
575 #ifdef PHP_WIN32
576 TCHAR aspell_dir[200];
577 TCHAR data_dir[220];
578 TCHAR dict_dir[220];
579 HKEY hkey;
580 DWORD dwType,dwLen;
581 #endif
582
583 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|sss", &language, &language_len, &spelling, &spelling_len,
584 &jargon, &jargon_len, &encoding, &encoding_len) == FAILURE) {
585 RETURN_THROWS();
586 }
587
588 config = new_pspell_config();
589
590 #ifdef PHP_WIN32
591 /* If aspell was installed using installer, we should have a key
592 * pointing to the location of the dictionaries
593 */
594 if (0 == RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Aspell", &hkey)) {
595 LONG result;
596 dwLen = sizeof(aspell_dir) - 1;
597 result = RegQueryValueEx(hkey, "", NULL, &dwType, (LPBYTE)&aspell_dir, &dwLen);
598 RegCloseKey(hkey);
599 if (result == ERROR_SUCCESS) {
600 strlcpy(data_dir, aspell_dir, sizeof(data_dir));
601 strlcat(data_dir, "\\data", sizeof(data_dir));
602 strlcpy(dict_dir, aspell_dir, sizeof(dict_dir));
603 strlcat(dict_dir, "\\dict", sizeof(dict_dir));
604
605 pspell_config_replace(config, "data-dir", data_dir);
606 pspell_config_replace(config, "dict-dir", dict_dir);
607 }
608 }
609 #endif
610
611 pspell_config_replace(config, "language-tag", language);
612
613 if (spelling_len) {
614 pspell_config_replace(config, "spelling", spelling);
615 }
616
617 if (jargon_len) {
618 pspell_config_replace(config, "jargon", jargon);
619 }
620
621 if (encoding_len) {
622 pspell_config_replace(config, "encoding", encoding);
623 }
624
625 /* By default I do not want to write anything anywhere because it'll try to write to $HOME
626 which is not what we want */
627 pspell_config_replace(config, "save-repl", "false");
628
629 object_init_ex(return_value, php_pspell_config_ce);
630 php_pspell_config_object_from_zend_object(Z_OBJ_P(return_value))->cfg = config;
631 }
632 /* }}} */
633
634 /* {{{ Consider run-together words as valid components */
PHP_FUNCTION(pspell_config_runtogether)635 PHP_FUNCTION(pspell_config_runtogether)
636 {
637 zval *zcfg;
638 bool runtogether;
639 PspellConfig *config;
640
641 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ob", &zcfg, php_pspell_config_ce, &runtogether) == FAILURE) {
642 RETURN_THROWS();
643 }
644 config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg;
645
646 pspell_config_replace(config, "run-together", runtogether ? "true" : "false");
647
648 RETURN_TRUE;
649 }
650 /* }}} */
651
652 /* {{{ Select mode for config (PSPELL_FAST, PSPELL_NORMAL or PSPELL_BAD_SPELLERS) */
PHP_FUNCTION(pspell_config_mode)653 PHP_FUNCTION(pspell_config_mode)
654 {
655 zval *zcfg;
656 zend_long mode;
657 PspellConfig *config;
658
659 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &zcfg, php_pspell_config_ce, &mode) == FAILURE) {
660 RETURN_THROWS();
661 }
662 config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg;
663
664 /* First check what mode we want (how many suggestions) */
665 if (mode == PSPELL_FAST) {
666 pspell_config_replace(config, "sug-mode", "fast");
667 } else if (mode == PSPELL_NORMAL) {
668 pspell_config_replace(config, "sug-mode", "normal");
669 } else if (mode == PSPELL_BAD_SPELLERS) {
670 pspell_config_replace(config, "sug-mode", "bad-spellers");
671 }
672
673 RETURN_TRUE;
674 }
675 /* }}} */
676
677 /* {{{ Ignore words <= n chars */
PHP_FUNCTION(pspell_config_ignore)678 PHP_FUNCTION(pspell_config_ignore)
679 {
680 char ignore_str[MAX_LENGTH_OF_LONG + 1];
681 zval *zcfg;
682 zend_long ignore = 0L;
683 PspellConfig *config;
684
685 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &zcfg, php_pspell_config_ce, &ignore) == FAILURE) {
686 RETURN_THROWS();
687 }
688 config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg;
689
690 snprintf(ignore_str, sizeof(ignore_str), ZEND_LONG_FMT, ignore);
691
692 pspell_config_replace(config, "ignore", ignore_str);
693 RETURN_TRUE;
694 }
695 /* }}} */
696
pspell_config_path(INTERNAL_FUNCTION_PARAMETERS,char * option)697 static void pspell_config_path(INTERNAL_FUNCTION_PARAMETERS, char *option)
698 {
699 zval *zcfg;
700 zend_string *value;
701 PspellConfig *config;
702
703 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OP", &zcfg, php_pspell_config_ce, &value) == FAILURE) {
704 RETURN_THROWS();
705 }
706 config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg;
707
708 if (php_check_open_basedir(ZSTR_VAL(value))) {
709 RETURN_FALSE;
710 }
711
712 pspell_config_replace(config, option, ZSTR_VAL(value));
713
714 RETURN_TRUE;
715 }
716
717 /* {{{ Use a personal dictionary for this config */
PHP_FUNCTION(pspell_config_personal)718 PHP_FUNCTION(pspell_config_personal)
719 {
720 pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "personal");
721 }
722 /* }}} */
723
724 /* {{{ location of the main word list */
PHP_FUNCTION(pspell_config_dict_dir)725 PHP_FUNCTION(pspell_config_dict_dir)
726 {
727 pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "dict-dir");
728 }
729 /* }}} */
730
731 /* {{{ location of language data files */
PHP_FUNCTION(pspell_config_data_dir)732 PHP_FUNCTION(pspell_config_data_dir)
733 {
734 pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "data-dir");
735 }
736 /* }}} */
737
738 /* {{{ Use a personal dictionary with replacement pairs for this config */
PHP_FUNCTION(pspell_config_repl)739 PHP_FUNCTION(pspell_config_repl)
740 {
741 zval *zcfg;
742 zend_string *repl;
743 PspellConfig *config;
744
745 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OP", &zcfg, php_pspell_config_ce, &repl) == FAILURE) {
746 RETURN_THROWS();
747 }
748 config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg;
749
750 pspell_config_replace(config, "save-repl", "true");
751
752 if (php_check_open_basedir(ZSTR_VAL(repl))) {
753 RETURN_FALSE;
754 }
755
756 pspell_config_replace(config, "repl", ZSTR_VAL(repl));
757
758 RETURN_TRUE;
759 }
760 /* }}} */
761
762 /* {{{ Save replacement pairs when personal list is saved for this config */
PHP_FUNCTION(pspell_config_save_repl)763 PHP_FUNCTION(pspell_config_save_repl)
764 {
765 zval *zcfg;
766 bool save;
767 PspellConfig *config;
768
769 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ob", &zcfg, php_pspell_config_ce, &save) == FAILURE) {
770 RETURN_THROWS();
771 }
772 config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg;
773
774 pspell_config_replace(config, "save-repl", save ? "true" : "false");
775
776 RETURN_TRUE;
777 }
778 /* }}} */
779
780 /* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(pspell)781 static PHP_MINFO_FUNCTION(pspell)
782 {
783 php_info_print_table_start();
784 php_info_print_table_row(2, "PSpell Support", "enabled");
785 php_info_print_table_end();
786 }
787 /* }}} */
788
789 #endif
790