xref: /PHP-7.3/ext/enchant/enchant.c (revision 6adb8859)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2018 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 ENCHANT_VERSION_STRING
319 	php_info_print_table_row(2, "Libenchant Version", ENCHANT_VERSION_STRING);
320 #elif defined(HAVE_ENCHANT_BROKER_SET_PARAM)
321 	php_info_print_table_row(2, "Libenchant Version", "1.5.0 or later");
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, "%s", "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, "%s", "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 string 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 		zval_ptr_dtor(sugg);
720 		array_init(sugg);
721 	}
722 
723 	PHP_ENCHANT_GET_DICT;
724 
725 	if (enchant_dict_check(pdict->pdict, word, wordlen) > 0) {
726 		size_t n_sugg;
727 		char **suggs;
728 
729 		if (!sugg && ZEND_NUM_ARGS() == 2) {
730 			RETURN_FALSE;
731 		}
732 
733 		suggs = enchant_dict_suggest(pdict->pdict, word, wordlen, &n_sugg);
734 		if (suggs && n_sugg) {
735 			size_t i;
736 			for (i = 0; i < n_sugg; i++) {
737 				add_next_index_string(sugg, suggs[i]);
738 			}
739 			enchant_dict_free_suggestions(pdict->pdict, suggs);
740 		}
741 
742 
743 		RETURN_FALSE;
744 	}
745 	RETURN_TRUE;
746 }
747 /* }}} */
748 
749 /* {{{ proto bool enchant_dict_check(resource dict, string word)
750     If the word is correctly spelled return true, otherwise return false */
PHP_FUNCTION(enchant_dict_check)751 PHP_FUNCTION(enchant_dict_check)
752 {
753 	zval *dict;
754 	char *word;
755 	size_t wordlen;
756 	enchant_dict *pdict;
757 
758 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &dict, &word, &wordlen) == FAILURE) {
759 		RETURN_FALSE;
760 	}
761 
762 	PHP_ENCHANT_GET_DICT;
763 
764 	RETURN_BOOL(!enchant_dict_check(pdict->pdict, word, wordlen));
765 }
766 /* }}} */
767 
768 /* {{{ proto array enchant_dict_suggest(resource dict, string word)
769     Will return a list of values if any of those pre-conditions are not met.*/
PHP_FUNCTION(enchant_dict_suggest)770 PHP_FUNCTION(enchant_dict_suggest)
771 {
772 	zval *dict;
773 	char *word;
774 	size_t wordlen;
775 	char **suggs;
776 	enchant_dict *pdict;
777 	size_t n_sugg;
778 
779 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &dict, &word, &wordlen) == FAILURE) {
780 		RETURN_FALSE;
781 	}
782 
783 	PHP_ENCHANT_GET_DICT;
784 
785 	suggs = enchant_dict_suggest(pdict->pdict, word, wordlen, &n_sugg);
786 	if (suggs && n_sugg) {
787 		size_t i;
788 
789 		array_init(return_value);
790 		for (i = 0; i < n_sugg; i++) {
791 			add_next_index_string(return_value, suggs[i]);
792 		}
793 
794 		enchant_dict_free_suggestions(pdict->pdict, suggs);
795 	}
796 }
797 /* }}} */
798 
799 /* {{{ proto void enchant_dict_add_to_personal(resource dict, string word)
800      add 'word' to personal word list */
PHP_FUNCTION(enchant_dict_add_to_personal)801 PHP_FUNCTION(enchant_dict_add_to_personal)
802 {
803 	zval *dict;
804 	char *word;
805 	size_t wordlen;
806 	enchant_dict *pdict;
807 
808 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &dict, &word, &wordlen) == FAILURE) {
809 		RETURN_FALSE;
810 	}
811 
812 	PHP_ENCHANT_GET_DICT;
813 
814 	enchant_dict_add_to_personal(pdict->pdict, word, wordlen);
815 }
816 /* }}} */
817 
818 /* {{{ proto void enchant_dict_add_to_session(resource dict, string word)
819    add 'word' to this spell-checking session */
PHP_FUNCTION(enchant_dict_add_to_session)820 PHP_FUNCTION(enchant_dict_add_to_session)
821 {
822 	zval *dict;
823 	char *word;
824 	size_t wordlen;
825 	enchant_dict *pdict;
826 
827 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &dict, &word, &wordlen) == FAILURE) {
828 		RETURN_FALSE;
829 	}
830 
831 	PHP_ENCHANT_GET_DICT;
832 
833 	enchant_dict_add_to_session(pdict->pdict, word, wordlen);
834 }
835 /* }}} */
836 
837 /* {{{ proto bool enchant_dict_is_in_session(resource dict, string word)
838    whether or not 'word' exists in this spelling-session */
PHP_FUNCTION(enchant_dict_is_in_session)839 PHP_FUNCTION(enchant_dict_is_in_session)
840 {
841 	zval *dict;
842 	char *word;
843 	size_t wordlen;
844 	enchant_dict *pdict;
845 
846 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &dict, &word, &wordlen) == FAILURE) {
847 		RETURN_FALSE;
848 	}
849 
850 	PHP_ENCHANT_GET_DICT;
851 
852 	RETURN_BOOL(enchant_dict_is_in_session(pdict->pdict, word, wordlen));
853 }
854 /* }}} */
855 
856 /* {{{ proto void enchant_dict_store_replacement(resource dict, string mis, string cor)
857 	add a correction for 'mis' using 'cor'.
858 	Notes that you replaced @mis with @cor, so it's possibly more likely
859 	that future occurrences of @mis will be replaced with @cor. So it might
860 	bump @cor up in the suggestion list.*/
PHP_FUNCTION(enchant_dict_store_replacement)861 PHP_FUNCTION(enchant_dict_store_replacement)
862 {
863 	zval *dict;
864 	char *mis, *cor;
865 	size_t mislen, corlen;
866 
867 	enchant_dict *pdict;
868 
869 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rss", &dict, &mis, &mislen, &cor, &corlen) == FAILURE) {
870 		RETURN_FALSE;
871 	}
872 
873 	PHP_ENCHANT_GET_DICT;
874 
875 	enchant_dict_store_replacement(pdict->pdict, mis, mislen, cor, corlen);
876 }
877 /* }}} */
878 
879 /* {{{ proto string enchant_dict_get_error(resource dict)
880    Returns the last error of the current spelling-session */
PHP_FUNCTION(enchant_dict_get_error)881 PHP_FUNCTION(enchant_dict_get_error)
882 {
883 	zval *dict;
884 	enchant_dict *pdict;
885 	char *msg;
886 
887 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &dict) == FAILURE) {
888 		RETURN_FALSE;
889 	}
890 
891 	PHP_ENCHANT_GET_DICT;
892 
893 	msg = enchant_dict_get_error(pdict->pdict);
894 	if (msg) {
895 		RETURN_STRING((char *)msg);
896 	}
897 
898 	RETURN_FALSE;
899 }
900 /* }}} */
901 
902 /* {{{ proto array enchant_dict_describe(resource dict)
903    Describes an individual dictionary 'dict' */
PHP_FUNCTION(enchant_dict_describe)904 PHP_FUNCTION(enchant_dict_describe)
905 {
906 	zval *dict;
907 	enchant_dict *pdict;
908 
909 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &dict) == FAILURE) {
910 		RETURN_FALSE;
911 	}
912 
913 	PHP_ENCHANT_GET_DICT;
914 
915 	enchant_dict_describe(pdict->pdict, describe_dict_fn, (void *)return_value);
916 }
917 /* }}} */
918 
919 /*
920  * Local variables:
921  * tab-width: 4
922  * c-basic-offset: 4
923  * End:
924  * vim600: noet sw=4 ts=4 fdm=marker
925  * vim<600: noet sw=4 ts=4
926  */
927