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