xref: /PHP-7.4/ext/enchant/enchant.c (revision 6adb8859)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) The PHP Group                                          |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.0 of the PHP license,       |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available at through the world-wide-web at                           |
10   | http://www.php.net/license/3_0.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: Pierre-Alain Joye <paj@pearfr.org>                           |
16   |         Ilia Alshanetsky <ilia@prohost.org>                          |
17   +----------------------------------------------------------------------+
18 */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include "php.h"
25 #include "php_ini.h"
26 #include "ext/standard/info.h"
27 #include <enchant.h>
28 #include "php_enchant.h"
29 
30 typedef EnchantBroker * EnchantBrokerPtr;
31 typedef struct _broker_struct enchant_broker;
32 typedef struct _dict_struct enchant_dict;
33 
34 typedef enchant_broker * enchant_brokerPtr;
35 typedef enchant_dict * enchant_dictPtr;
36 
37 typedef struct _broker_struct {
38 	EnchantBroker	*pbroker;
39 	enchant_dict	**dict;
40 	unsigned int	dictcnt;
41 	zend_resource	*rsrc;
42 } _enchant_broker;
43 
44 typedef struct _dict_struct {
45 	unsigned int	id;
46 	EnchantDict		*pdict;
47 	enchant_broker	*pbroker;
48 	zend_resource	*rsrc;
49 } _enchant_dict;
50 
51 
52 /* True global resources - no need for thread safety here */
53 static int le_enchant_broker;
54 static int le_enchant_dict;
55 
56 /* If you declare any globals in php_enchant.h uncomment this:*/
57 /*ZEND_DECLARE_MODULE_GLOBALS(enchant)*/
58 
59 #define PHP_ENCHANT_MYSPELL 1
60 #define PHP_ENCHANT_ISPELL 2
61 
62 /* {{{ arginfo */
63 ZEND_BEGIN_ARG_INFO(arginfo_enchant_broker_init, 0)
64 ZEND_END_ARG_INFO()
65 
66 ZEND_BEGIN_ARG_INFO_EX(arginfo_enchant_broker_free, 0, 0, 1)
67 	ZEND_ARG_INFO(0, broker)
68 ZEND_END_ARG_INFO()
69 
70 ZEND_BEGIN_ARG_INFO_EX(arginfo_enchant_broker_set_dict_path, 0, 0, 3)
71 	ZEND_ARG_INFO(0, broker)
72 	ZEND_ARG_INFO(0, name)
73 	ZEND_ARG_INFO(0, value)
74 ZEND_END_ARG_INFO()
75 
76 ZEND_BEGIN_ARG_INFO_EX(arginfo_enchant_broker_get_dict_path, 0, 0, 2)
77 	ZEND_ARG_INFO(0, broker)
78 	ZEND_ARG_INFO(0, name)
79 ZEND_END_ARG_INFO()
80 
81 ZEND_BEGIN_ARG_INFO_EX(arginfo_enchant_broker_request_dict, 0, 0, 2)
82 	ZEND_ARG_INFO(0, broker)
83 	ZEND_ARG_INFO(0, tag)
84 ZEND_END_ARG_INFO()
85 
86 ZEND_BEGIN_ARG_INFO_EX(arginfo_enchant_broker_request_pwl_dict, 0, 0, 2)
87 	ZEND_ARG_INFO(0, broker)
88 	ZEND_ARG_INFO(0, filename)
89 ZEND_END_ARG_INFO()
90 
91 ZEND_BEGIN_ARG_INFO_EX(arginfo_enchant_broker_free_dict, 0, 0, 1)
92 	ZEND_ARG_INFO(0, dict)
93 ZEND_END_ARG_INFO()
94 
95 ZEND_BEGIN_ARG_INFO_EX(arginfo_enchant_broker_set_ordering, 0, 0, 3)
96 	ZEND_ARG_INFO(0, broker)
97 	ZEND_ARG_INFO(0, tag)
98 	ZEND_ARG_INFO(0, ordering)
99 ZEND_END_ARG_INFO()
100 
101 ZEND_BEGIN_ARG_INFO_EX(arginfo_enchant_dict_quick_check, 0, 0, 2)
102 	ZEND_ARG_INFO(0, dict)
103 	ZEND_ARG_INFO(0, word)
104 	ZEND_ARG_INFO(1, suggestions)
105 ZEND_END_ARG_INFO()
106 
107 ZEND_BEGIN_ARG_INFO_EX(arginfo_enchant_dict_check, 0, 0, 2)
108 	ZEND_ARG_INFO(0, dict)
109 	ZEND_ARG_INFO(0, word)
110 ZEND_END_ARG_INFO()
111 
112 ZEND_BEGIN_ARG_INFO_EX(arginfo_enchant_dict_store_replacement, 0, 0, 3)
113 	ZEND_ARG_INFO(0, dict)
114 	ZEND_ARG_INFO(0, mis)
115 	ZEND_ARG_INFO(0, cor)
116 ZEND_END_ARG_INFO()
117 /* }}} */
118 
119 /* {{{ enchant_functions[]
120  *
121  * Every user visible function must have an entry in enchant_functions[].
122  */
123 static const zend_function_entry enchant_functions[] = {
124 	PHP_FE(enchant_broker_init, 			arginfo_enchant_broker_init)
125 	PHP_FE(enchant_broker_free, 			arginfo_enchant_broker_free)
126 	PHP_FE(enchant_broker_get_error, 		arginfo_enchant_broker_free)
127 	PHP_FE(enchant_broker_set_dict_path,	arginfo_enchant_broker_set_dict_path)
128 	PHP_FE(enchant_broker_get_dict_path,	arginfo_enchant_broker_get_dict_path)
129 	PHP_FE(enchant_broker_list_dicts, 		arginfo_enchant_broker_free)
130 	PHP_FE(enchant_broker_request_dict,		arginfo_enchant_broker_request_dict)
131 	PHP_FE(enchant_broker_request_pwl_dict, arginfo_enchant_broker_request_pwl_dict)
132 	PHP_FE(enchant_broker_free_dict, 		arginfo_enchant_broker_free_dict)
133 	PHP_FE(enchant_broker_dict_exists, 		arginfo_enchant_broker_request_dict)
134 	PHP_FE(enchant_broker_set_ordering, 	arginfo_enchant_broker_set_ordering)
135 	PHP_FE(enchant_broker_describe, 		arginfo_enchant_broker_free)
136 	PHP_FE(enchant_dict_check, 				arginfo_enchant_dict_check)
137 	PHP_FE(enchant_dict_suggest, 			arginfo_enchant_dict_check)
138 	PHP_FE(enchant_dict_add_to_personal, 	arginfo_enchant_dict_check)
139 	PHP_FE(enchant_dict_add_to_session, 	arginfo_enchant_dict_check)
140 	PHP_FE(enchant_dict_is_in_session, 		arginfo_enchant_dict_check)
141 	PHP_FE(enchant_dict_store_replacement, 	arginfo_enchant_dict_store_replacement)
142 	PHP_FE(enchant_dict_get_error, 			arginfo_enchant_broker_free_dict)
143 	PHP_FE(enchant_dict_describe, 			arginfo_enchant_broker_free_dict)
144 	PHP_FE(enchant_dict_quick_check, 		arginfo_enchant_dict_quick_check)
145 	PHP_FE_END
146 };
147 /* }}} */
148 
149 /* {{{ enchant_module_entry
150  */
151 zend_module_entry enchant_module_entry = {
152 	STANDARD_MODULE_HEADER,
153 	"enchant",
154 	enchant_functions,
155 	PHP_MINIT(enchant),
156 	PHP_MSHUTDOWN(enchant),
157 	NULL,	/* Replace with NULL if there's nothing to do at request start */
158 	NULL,	/* Replace with NULL if there's nothing to do at request end */
159 	PHP_MINFO(enchant),
160 	PHP_ENCHANT_VERSION,
161 	STANDARD_MODULE_PROPERTIES
162 };
163 /* }}} */
164 
165 #ifdef COMPILE_DL_ENCHANT
ZEND_GET_MODULE(enchant)166 ZEND_GET_MODULE(enchant)
167 #endif
168 
169 static void
170 enumerate_providers_fn (const char * const name,
171                         const char * const desc,
172                         const char * const file,
173                         void * ud) /* {{{ */
174 {
175 	zval *zdesc = (zval *) ud;
176 	zval tmp_array;
177 
178 	array_init(&tmp_array);
179 
180 	add_assoc_string(&tmp_array, "name", (char *)name);
181 	add_assoc_string(&tmp_array, "desc", (char *)desc);
182 	add_assoc_string(&tmp_array, "file", (char *)file);
183 
184 	if (Z_TYPE_P(zdesc)!=IS_ARRAY) {
185 		array_init(zdesc);
186 	}
187 
188 	add_next_index_zval(zdesc, &tmp_array);
189 }
190 /* }}} */
191 
192 static void
describe_dict_fn(const char * const lang,const char * const name,const char * const desc,const char * const file,void * ud)193 describe_dict_fn (const char * const lang,
194                   const char * const name,
195                   const char * const desc,
196                   const char * const file,
197                   void * ud) /* {{{ */
198 {
199 	zval *zdesc = (zval *) ud;
200 	array_init(zdesc);
201 	add_assoc_string(zdesc, "lang", (char *)lang);
202 	add_assoc_string(zdesc, "name", (char *)name);
203 	add_assoc_string(zdesc, "desc", (char *)desc);
204 	add_assoc_string(zdesc, "file", (char *)file);
205 }
206 /* }}} */
207 
php_enchant_list_dicts_fn(const char * const lang_tag,const char * const provider_name,const char * const provider_desc,const char * const provider_file,void * ud)208 static void php_enchant_list_dicts_fn( const char * const lang_tag,
209 	   	const char * const provider_name, const char * const provider_desc,
210 		const char * const provider_file, void * ud) /* {{{ */
211 {
212 	zval *zdesc = (zval *) ud;
213 	zval tmp_array;
214 
215 	array_init(&tmp_array);
216 	add_assoc_string(&tmp_array, "lang_tag", (char *)lang_tag);
217 	add_assoc_string(&tmp_array, "provider_name", (char *)provider_name);
218 	add_assoc_string(&tmp_array, "provider_desc", (char *)provider_desc);
219 	add_assoc_string(&tmp_array, "provider_file", (char *)provider_file);
220 
221 	if (Z_TYPE_P(zdesc) != IS_ARRAY) {
222 		array_init(zdesc);
223 	}
224 	add_next_index_zval(zdesc, &tmp_array);
225 
226 }
227 /* }}} */
228 
php_enchant_broker_free(zend_resource * rsrc)229 static void php_enchant_broker_free(zend_resource *rsrc) /* {{{ */
230 {
231 	if (rsrc->ptr) {
232 		enchant_broker *broker = (enchant_broker *)rsrc->ptr;
233 		if (broker) {
234 			if (broker->pbroker) {
235 				if (broker->dictcnt && broker->dict) {
236 					if (broker->dict) {
237 						int total;
238 						total = broker->dictcnt-1;
239 						do {
240 							if (broker->dict[total]) {
241 								enchant_dict *pdict = broker->dict[total];
242 								broker->dict[total] = NULL;
243 								zend_list_free(pdict->rsrc);
244 								efree(pdict);
245 							}
246 							total--;
247 						} while (total>=0);
248 					}
249 					efree(broker->dict);
250 					broker->dict = NULL;
251 				}
252 				enchant_broker_free(broker->pbroker);
253 			}
254 			efree(broker);
255 		}
256 	}
257 }
258 /* }}} */
259 
php_enchant_dict_free(zend_resource * rsrc)260 static void php_enchant_dict_free(zend_resource *rsrc) /* {{{ */
261 
262 {
263 	if (rsrc->ptr) {
264 		enchant_dict *pdict = (enchant_dict *)rsrc->ptr;
265 		if (pdict) {
266 			enchant_broker *pbroker = pdict->pbroker;
267 
268 			if (pdict->pdict && pbroker) {
269 				enchant_broker_free_dict(pbroker->pbroker, pdict->pdict);
270 			}
271 
272 			pbroker->dict[pdict->id] = NULL;
273 			efree(pdict);
274 			zend_list_delete(pbroker->rsrc);
275 		}
276 	}
277 }
278 /* }}} */
279 
280 /* {{{ PHP_MINIT_FUNCTION
281  */
PHP_MINIT_FUNCTION(enchant)282 PHP_MINIT_FUNCTION(enchant)
283 {
284 	le_enchant_broker = zend_register_list_destructors_ex(php_enchant_broker_free, NULL, "enchant_broker", module_number);
285 	le_enchant_dict = zend_register_list_destructors_ex(php_enchant_dict_free, NULL, "enchant_dict", module_number);
286 	REGISTER_LONG_CONSTANT("ENCHANT_MYSPELL", PHP_ENCHANT_MYSPELL, CONST_CS | CONST_PERSISTENT);
287 	REGISTER_LONG_CONSTANT("ENCHANT_ISPELL", PHP_ENCHANT_ISPELL, CONST_CS | CONST_PERSISTENT);
288 	return SUCCESS;
289 }
290 /* }}} */
291 
292 /* {{{ PHP_MSHUTDOWN_FUNCTION
293  */
PHP_MSHUTDOWN_FUNCTION(enchant)294 PHP_MSHUTDOWN_FUNCTION(enchant)
295 {
296 	return SUCCESS;
297 }
298 /* }}} */
299 
__enumerate_providers_fn(const char * const name,const char * const desc,const char * const file,void * ud)300 static void __enumerate_providers_fn (const char * const name,
301                         const char * const desc,
302                         const char * const file,
303                         void * ud) /* {{{ */
304 {
305 	php_info_print_table_row(3, name, desc, file);
306 }
307 /* }}} */
308 
309 /* {{{ PHP_MINFO_FUNCTION
310  */
PHP_MINFO_FUNCTION(enchant)311 PHP_MINFO_FUNCTION(enchant)
312 {
313 	EnchantBroker *pbroker;
314 
315 	pbroker = enchant_broker_init();
316 	php_info_print_table_start();
317 	php_info_print_table_row(2, "enchant support", "enabled");
318 #ifdef HAVE_ENCHANT_GET_VERSION
319 	php_info_print_table_row(2, "Libenchant Version", enchant_get_version());
320 #elif defined(HAVE_ENCHANT_BROKER_SET_PARAM)
321 	php_info_print_table_row(2, "Libenchant Version", "1.5.x");
322 #endif
323 	php_info_print_table_end();
324 
325 	php_info_print_table_start();
326 	enchant_broker_describe(pbroker, __enumerate_providers_fn, NULL);
327 	php_info_print_table_end();
328 	enchant_broker_free(pbroker);
329 }
330 /* }}} */
331 
332 #define PHP_ENCHANT_GET_BROKER	\
333 	pbroker = (enchant_broker *)zend_fetch_resource(Z_RES_P(broker), "enchant_broker", le_enchant_broker); \
334 	if (!pbroker || !pbroker->pbroker) {	\
335 		php_error_docref(NULL, E_WARNING, "Resource broker invalid");	\
336 		RETURN_FALSE;	\
337 	}
338 
339 #define PHP_ENCHANT_GET_DICT	\
340 	pdict = (enchant_dict *)zend_fetch_resource(Z_RES_P(dict), "enchant_dict", le_enchant_dict); \
341 	if (!pdict || !pdict->pdict) {	\
342 		php_error_docref(NULL, E_WARNING, "Invalid dictionary resource.");	\
343 		RETURN_FALSE;	\
344 	}
345 
346 /* {{{ proto resource enchant_broker_init()
347    create a new broker object capable of requesting */
PHP_FUNCTION(enchant_broker_init)348 PHP_FUNCTION(enchant_broker_init)
349 {
350 	enchant_broker *broker;
351 	EnchantBroker *pbroker;
352 
353 	if (zend_parse_parameters_none() == FAILURE) {
354 		return;
355 	}
356 
357 	pbroker = enchant_broker_init();
358 
359 	if (pbroker) {
360 		broker = (enchant_broker *) emalloc(sizeof(enchant_broker));
361 		broker->pbroker = pbroker;
362 		broker->dict = NULL;
363 		broker->dictcnt = 0;
364 		broker->rsrc = zend_register_resource(broker, le_enchant_broker);
365 		RETURN_RES(broker->rsrc);
366 	} else {
367 		RETURN_FALSE;
368 	}
369 }
370 /* }}} */
371 
372 /* {{{ proto bool enchant_broker_free(resource broker)
373    Destroys the broker object and its dictionnaries */
PHP_FUNCTION(enchant_broker_free)374 PHP_FUNCTION(enchant_broker_free)
375 {
376 	zval *broker;
377 	enchant_broker *pbroker;
378 
379 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &broker) == FAILURE) {
380 		RETURN_FALSE;
381 	}
382 	PHP_ENCHANT_GET_BROKER;
383 
384 	zend_list_close(Z_RES_P(broker));
385 	RETURN_TRUE;
386 }
387 /* }}} */
388 
389 /* {{{ proto string enchant_broker_get_error(resource broker)
390    Returns the last error of the broker */
PHP_FUNCTION(enchant_broker_get_error)391 PHP_FUNCTION(enchant_broker_get_error)
392 {
393 	zval *broker;
394 	enchant_broker *pbroker;
395 	char *msg;
396 
397 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &broker) == FAILURE) {
398 		RETURN_FALSE;
399 	}
400 
401 	PHP_ENCHANT_GET_BROKER;
402 
403 	msg = enchant_broker_get_error(pbroker->pbroker);
404 	if (msg) {
405 		RETURN_STRING((char *)msg);
406 	}
407 	RETURN_FALSE;
408 }
409 /* }}} */
410 
411 #if HAVE_ENCHANT_BROKER_SET_PARAM
412 /* {{{ proto bool enchant_broker_set_dict_path(resource broker, int dict_type, string value)
413 	Set the directory path for a given backend, works with ispell and myspell */
PHP_FUNCTION(enchant_broker_set_dict_path)414 PHP_FUNCTION(enchant_broker_set_dict_path)
415 {
416 	zval *broker;
417 	enchant_broker *pbroker;
418 	zend_long dict_type;
419 	char *value;
420 	size_t value_len;
421 
422 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rls", &broker, &dict_type, &value, &value_len) == FAILURE) {
423 		RETURN_FALSE;
424 	}
425 
426 	if (!value_len) {
427 		RETURN_FALSE;
428 	}
429 
430 	PHP_ENCHANT_GET_BROKER;
431 
432 	switch (dict_type) {
433 		case PHP_ENCHANT_MYSPELL:
434 			PHP_ENCHANT_GET_BROKER;
435 			enchant_broker_set_param(pbroker->pbroker, "enchant.myspell.dictionary.path", (const char *)value);
436 			RETURN_TRUE;
437 			break;
438 
439 		case PHP_ENCHANT_ISPELL:
440 			PHP_ENCHANT_GET_BROKER;
441 			enchant_broker_set_param(pbroker->pbroker, "enchant.ispell.dictionary.path", (const char *)value);
442 			RETURN_TRUE;
443 			break;
444 
445 		default:
446 			RETURN_FALSE;
447 	}
448 }
449 /* }}} */
450 
451 
452 /* {{{ proto string enchant_broker_get_dict_path(resource broker, int dict_type)
453 	Get the directory path for a given backend, works with ispell and myspell */
PHP_FUNCTION(enchant_broker_get_dict_path)454 PHP_FUNCTION(enchant_broker_get_dict_path)
455 {
456 	zval *broker;
457 	enchant_broker *pbroker;
458 	zend_long dict_type;
459 	char *value;
460 
461 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &broker, &dict_type) == FAILURE) {
462 		RETURN_FALSE;
463 	}
464 
465 	PHP_ENCHANT_GET_BROKER;
466 
467 	switch (dict_type) {
468 		case PHP_ENCHANT_MYSPELL:
469 			PHP_ENCHANT_GET_BROKER;
470 			value = enchant_broker_get_param(pbroker->pbroker, "enchant.myspell.dictionary.path");
471 			break;
472 
473 		case PHP_ENCHANT_ISPELL:
474 			PHP_ENCHANT_GET_BROKER;
475 			value = enchant_broker_get_param(pbroker->pbroker, "enchant.ispell.dictionary.path");
476 			break;
477 
478 		default:
479 			RETURN_FALSE;
480 	}
481 
482 	if (value == NULL) {
483 		php_error_docref(NULL, E_WARNING, "dict_path not set");
484 		RETURN_FALSE;
485 	}
486 
487 	RETURN_STRING(value);
488 }
489 /* }}} */
490 #else
491 /* {{{ proto bool enchant_broker_set_dict_path(resource broker, int dict_type, string value)
492 	Set the directory path for a given backend, works with ispell and myspell */
PHP_FUNCTION(enchant_broker_set_dict_path)493 PHP_FUNCTION(enchant_broker_set_dict_path)
494 {
495 	RETURN_FALSE;
496 }
497 /* }}} */
498 
499 
500 /* {{{ proto string enchant_broker_get_dict_path(resource broker, int dict_type)
501 	Get the directory path for a given backend, works with ispell and myspell */
PHP_FUNCTION(enchant_broker_get_dict_path)502 PHP_FUNCTION(enchant_broker_get_dict_path)
503 {
504 	RETURN_FALSE;
505 }
506 /* }}} */
507 #endif
508 
509 /* {{{ proto array enchant_broker_list_dicts(resource broker)
510    Lists the dictionaries available for the given broker */
PHP_FUNCTION(enchant_broker_list_dicts)511 PHP_FUNCTION(enchant_broker_list_dicts)
512 {
513 	zval *broker;
514 	enchant_broker *pbroker;
515 
516 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &broker) == FAILURE) {
517 		RETURN_FALSE;
518 	}
519 
520 	PHP_ENCHANT_GET_BROKER;
521 
522 	enchant_broker_list_dicts(pbroker->pbroker, php_enchant_list_dicts_fn, (void *)return_value);
523 }
524 /* }}} */
525 
526 /* {{{ proto resource enchant_broker_request_dict(resource broker, string tag)
527 	create a new dictionary using tag, the non-empty language tag you wish to request
528 	a dictionary for ("en_US", "de_DE", ...) */
PHP_FUNCTION(enchant_broker_request_dict)529 PHP_FUNCTION(enchant_broker_request_dict)
530 {
531 	zval *broker;
532 	enchant_broker *pbroker;
533 	enchant_dict *dict;
534 	EnchantDict *d;
535 	char *tag;
536 	size_t taglen;
537 	int pos;
538 
539 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &broker, &tag, &taglen) == FAILURE) {
540 		RETURN_FALSE;
541 	}
542 
543 	PHP_ENCHANT_GET_BROKER;
544 
545 	if (taglen == 0) {
546 		php_error_docref(NULL, E_WARNING, "Tag cannot be empty");
547 		RETURN_FALSE;
548 	}
549 
550 	d = enchant_broker_request_dict(pbroker->pbroker, (const char *)tag);
551 	if (d) {
552 		pos = pbroker->dictcnt++;
553 		if (pbroker->dictcnt) {
554 			pbroker->dict = (enchant_dict **)erealloc(pbroker->dict, sizeof(enchant_dict *) * pbroker->dictcnt);
555 		} else {
556 			pbroker->dict = (enchant_dict **)emalloc(sizeof(enchant_dict *));
557 			pos = 0;
558 		}
559 
560 		dict = pbroker->dict[pos] = (enchant_dict *)emalloc(sizeof(enchant_dict));
561 		dict->id = pos;
562 		dict->pbroker = pbroker;
563 		dict->pdict = d;
564 		pbroker->dict[pos] = dict;
565 
566 		dict->rsrc = zend_register_resource(dict, le_enchant_dict);
567 		GC_ADDREF(pbroker->rsrc);
568 		RETURN_RES(dict->rsrc);
569 	} else {
570 		RETURN_FALSE;
571 	}
572 }
573 /* }}} */
574 
575 /* {{{ proto resource enchant_broker_request_pwl_dict(resource broker, string filename)
576    creates a dictionary using a PWL file. A PWL file is personal word file one word per line. It must exist before the call.*/
PHP_FUNCTION(enchant_broker_request_pwl_dict)577 PHP_FUNCTION(enchant_broker_request_pwl_dict)
578 {
579 	zval *broker;
580 	enchant_broker *pbroker;
581 	enchant_dict *dict;
582 	EnchantDict *d;
583 	char *pwl;
584 	size_t pwllen;
585 	int pos;
586 
587 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rp", &broker, &pwl, &pwllen) == FAILURE) {
588 		RETURN_FALSE;
589 	}
590 
591 	if (php_check_open_basedir(pwl)) {
592 		RETURN_FALSE;
593 	}
594 
595 	PHP_ENCHANT_GET_BROKER;
596 
597 	d = enchant_broker_request_pwl_dict(pbroker->pbroker, (const char *)pwl);
598 	if (d) {
599 		pos = pbroker->dictcnt++;
600 		if (pbroker->dictcnt) {
601 			pbroker->dict = (enchant_dict **)erealloc(pbroker->dict, sizeof(enchant_dict *) * pbroker->dictcnt);
602 		} else {
603 			pbroker->dict = (enchant_dict **)emalloc(sizeof(enchant_dict *));
604 			pos = 0;
605 		}
606 
607 		dict = pbroker->dict[pos] = (enchant_dict *)emalloc(sizeof(enchant_dict));
608 		dict->id = pos;
609 		dict->pbroker = pbroker;
610 		dict->pdict = d;
611 		pbroker->dict[pos] = dict;
612 
613 		dict->rsrc = zend_register_resource(dict, le_enchant_dict);
614 		GC_ADDREF(pbroker->rsrc);
615 		RETURN_RES(dict->rsrc);
616 	} else {
617 		RETURN_FALSE;
618 	}
619 }
620 /* }}} */
621 
622 /* {{{ proto resource enchant_broker_free_dict(resource dict)
623    Free the dictionary resource */
PHP_FUNCTION(enchant_broker_free_dict)624 PHP_FUNCTION(enchant_broker_free_dict)
625 {
626 	zval *dict;
627 	enchant_dict *pdict;
628 
629 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &dict) == FAILURE) {
630 		RETURN_FALSE;
631 	}
632 
633 	PHP_ENCHANT_GET_DICT;
634 
635 	zend_list_close(Z_RES_P(dict));
636 	RETURN_TRUE;
637 }
638 /* }}} */
639 
640 /* {{{ proto bool enchant_broker_dict_exists(resource broker, string tag)
641    Whether a dictionary exists or not. Using non-empty tag */
PHP_FUNCTION(enchant_broker_dict_exists)642 PHP_FUNCTION(enchant_broker_dict_exists)
643 {
644 	zval *broker;
645 	char *tag;
646 	size_t taglen;
647 	enchant_broker * pbroker;
648 
649 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &broker, &tag, &taglen) == FAILURE) {
650 		RETURN_FALSE;
651 	}
652 
653 	PHP_ENCHANT_GET_BROKER;
654 
655 	RETURN_BOOL(enchant_broker_dict_exists(pbroker->pbroker, tag));
656 }
657 /* }}} */
658 
659 /* {{{ proto bool enchant_broker_set_ordering(resource broker, string tag, string ordering)
660 	Declares a preference of dictionaries to use for the language
661 	described/referred to by 'tag'. The ordering is a comma delimited
662 	list of provider names. As a special exception, the "*" tag can
663 	be used as a language tag to declare a default ordering for any
664 	language that does not explicitly declare an ordering. */
665 
PHP_FUNCTION(enchant_broker_set_ordering)666 PHP_FUNCTION(enchant_broker_set_ordering)
667 {
668 	zval *broker;
669 	char *pordering;
670 	size_t porderinglen;
671 	char *ptag;
672 	size_t ptaglen;
673 	enchant_broker * pbroker;
674 
675 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rss", &broker, &ptag, &ptaglen, &pordering, &porderinglen) == FAILURE) {
676 		RETURN_FALSE;
677 	}
678 
679 	PHP_ENCHANT_GET_BROKER;
680 
681 	enchant_broker_set_ordering(pbroker->pbroker, ptag, pordering);
682 	RETURN_TRUE;
683 }
684 /* }}} */
685 
686 /* {{{ proto array enchant_broker_describe(resource broker)
687 	Enumerates the Enchant providers and tells you some rudimentary information about them. The same info is provided through phpinfo() */
PHP_FUNCTION(enchant_broker_describe)688 PHP_FUNCTION(enchant_broker_describe)
689 {
690 	EnchantBrokerDescribeFn describetozval = enumerate_providers_fn;
691 	zval *broker;
692 	enchant_broker * pbroker;
693 
694 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &broker) == FAILURE) {
695 		RETURN_FALSE;
696 	}
697 
698 	PHP_ENCHANT_GET_BROKER;
699 
700 	enchant_broker_describe(pbroker->pbroker, describetozval, (void *)return_value);
701 }
702 /* }}} */
703 
704 /* {{{ proto bool enchant_dict_quick_check(resource dict, string word [, array &suggestions])
705     If the word is correctly spelled return true, otherwise return false, if suggestions variable
706     is provided, fill it with spelling alternatives. */
PHP_FUNCTION(enchant_dict_quick_check)707 PHP_FUNCTION(enchant_dict_quick_check)
708 {
709 	zval *dict, *sugg = NULL;
710 	char *word;
711 	size_t wordlen;
712 	enchant_dict *pdict;
713 
714 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|z", &dict, &word, &wordlen, &sugg) == FAILURE) {
715 		RETURN_FALSE;
716 	}
717 
718 	if (sugg) {
719 		sugg = zend_try_array_init(sugg);
720 		if (!sugg) {
721 			return;
722 		}
723 	}
724 
725 	PHP_ENCHANT_GET_DICT;
726 
727 	if (enchant_dict_check(pdict->pdict, word, wordlen) > 0) {
728 		size_t n_sugg;
729 		char **suggs;
730 
731 		if (!sugg && ZEND_NUM_ARGS() == 2) {
732 			RETURN_FALSE;
733 		}
734 
735 		suggs = enchant_dict_suggest(pdict->pdict, word, wordlen, &n_sugg);
736 		if (suggs && n_sugg) {
737 			size_t i;
738 			for (i = 0; i < n_sugg; i++) {
739 				add_next_index_string(sugg, suggs[i]);
740 			}
741 			enchant_dict_free_suggestions(pdict->pdict, suggs);
742 		}
743 
744 
745 		RETURN_FALSE;
746 	}
747 	RETURN_TRUE;
748 }
749 /* }}} */
750 
751 /* {{{ proto bool enchant_dict_check(resource dict, string word)
752     If the word is correctly spelled return true, otherwise return false */
PHP_FUNCTION(enchant_dict_check)753 PHP_FUNCTION(enchant_dict_check)
754 {
755 	zval *dict;
756 	char *word;
757 	size_t wordlen;
758 	enchant_dict *pdict;
759 
760 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &dict, &word, &wordlen) == FAILURE) {
761 		RETURN_FALSE;
762 	}
763 
764 	PHP_ENCHANT_GET_DICT;
765 
766 	RETURN_BOOL(!enchant_dict_check(pdict->pdict, word, wordlen));
767 }
768 /* }}} */
769 
770 /* {{{ proto array enchant_dict_suggest(resource dict, string word)
771     Will return a list of values if any of those pre-conditions are not met.*/
PHP_FUNCTION(enchant_dict_suggest)772 PHP_FUNCTION(enchant_dict_suggest)
773 {
774 	zval *dict;
775 	char *word;
776 	size_t wordlen;
777 	char **suggs;
778 	enchant_dict *pdict;
779 	size_t n_sugg;
780 
781 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &dict, &word, &wordlen) == FAILURE) {
782 		RETURN_FALSE;
783 	}
784 
785 	PHP_ENCHANT_GET_DICT;
786 
787 	suggs = enchant_dict_suggest(pdict->pdict, word, wordlen, &n_sugg);
788 	if (suggs && n_sugg) {
789 		size_t i;
790 
791 		array_init(return_value);
792 		for (i = 0; i < n_sugg; i++) {
793 			add_next_index_string(return_value, suggs[i]);
794 		}
795 
796 		enchant_dict_free_suggestions(pdict->pdict, suggs);
797 	}
798 }
799 /* }}} */
800 
801 /* {{{ proto void enchant_dict_add_to_personal(resource dict, string word)
802      add 'word' to personal word list */
PHP_FUNCTION(enchant_dict_add_to_personal)803 PHP_FUNCTION(enchant_dict_add_to_personal)
804 {
805 	zval *dict;
806 	char *word;
807 	size_t wordlen;
808 	enchant_dict *pdict;
809 
810 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &dict, &word, &wordlen) == FAILURE) {
811 		RETURN_FALSE;
812 	}
813 
814 	PHP_ENCHANT_GET_DICT;
815 
816 	enchant_dict_add_to_personal(pdict->pdict, word, wordlen);
817 }
818 /* }}} */
819 
820 /* {{{ proto void enchant_dict_add_to_session(resource dict, string word)
821    add 'word' to this spell-checking session */
PHP_FUNCTION(enchant_dict_add_to_session)822 PHP_FUNCTION(enchant_dict_add_to_session)
823 {
824 	zval *dict;
825 	char *word;
826 	size_t wordlen;
827 	enchant_dict *pdict;
828 
829 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &dict, &word, &wordlen) == FAILURE) {
830 		RETURN_FALSE;
831 	}
832 
833 	PHP_ENCHANT_GET_DICT;
834 
835 	enchant_dict_add_to_session(pdict->pdict, word, wordlen);
836 }
837 /* }}} */
838 
839 /* {{{ proto bool enchant_dict_is_in_session(resource dict, string word)
840    whether or not 'word' exists in this spelling-session */
PHP_FUNCTION(enchant_dict_is_in_session)841 PHP_FUNCTION(enchant_dict_is_in_session)
842 {
843 	zval *dict;
844 	char *word;
845 	size_t wordlen;
846 	enchant_dict *pdict;
847 
848 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &dict, &word, &wordlen) == FAILURE) {
849 		RETURN_FALSE;
850 	}
851 
852 	PHP_ENCHANT_GET_DICT;
853 
854 	RETURN_BOOL(enchant_dict_is_in_session(pdict->pdict, word, wordlen));
855 }
856 /* }}} */
857 
858 /* {{{ proto void enchant_dict_store_replacement(resource dict, string mis, string cor)
859 	add a correction for 'mis' using 'cor'.
860 	Notes that you replaced @mis with @cor, so it's possibly more likely
861 	that future occurrences of @mis will be replaced with @cor. So it might
862 	bump @cor up in the suggestion list.*/
PHP_FUNCTION(enchant_dict_store_replacement)863 PHP_FUNCTION(enchant_dict_store_replacement)
864 {
865 	zval *dict;
866 	char *mis, *cor;
867 	size_t mislen, corlen;
868 
869 	enchant_dict *pdict;
870 
871 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rss", &dict, &mis, &mislen, &cor, &corlen) == FAILURE) {
872 		RETURN_FALSE;
873 	}
874 
875 	PHP_ENCHANT_GET_DICT;
876 
877 	enchant_dict_store_replacement(pdict->pdict, mis, mislen, cor, corlen);
878 }
879 /* }}} */
880 
881 /* {{{ proto string enchant_dict_get_error(resource dict)
882    Returns the last error of the current spelling-session */
PHP_FUNCTION(enchant_dict_get_error)883 PHP_FUNCTION(enchant_dict_get_error)
884 {
885 	zval *dict;
886 	enchant_dict *pdict;
887 	char *msg;
888 
889 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &dict) == FAILURE) {
890 		RETURN_FALSE;
891 	}
892 
893 	PHP_ENCHANT_GET_DICT;
894 
895 	msg = enchant_dict_get_error(pdict->pdict);
896 	if (msg) {
897 		RETURN_STRING((char *)msg);
898 	}
899 
900 	RETURN_FALSE;
901 }
902 /* }}} */
903 
904 /* {{{ proto array enchant_dict_describe(resource dict)
905    Describes an individual dictionary 'dict' */
PHP_FUNCTION(enchant_dict_describe)906 PHP_FUNCTION(enchant_dict_describe)
907 {
908 	zval *dict;
909 	enchant_dict *pdict;
910 
911 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &dict) == FAILURE) {
912 		RETURN_FALSE;
913 	}
914 
915 	PHP_ENCHANT_GET_DICT;
916 
917 	enchant_dict_describe(pdict->pdict, describe_dict_fn, (void *)return_value);
918 }
919 /* }}} */
920