xref: /PHP-7.2/ext/enchant/enchant.c (revision 7ba70a5f)
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   $Id: 24343b1598c9d96caf2ee8ea0fc956004fdcd69c $
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_check_open_basedir(pwl)) {
595 		RETURN_FALSE;
596 	}
597 
598 	PHP_ENCHANT_GET_BROKER;
599 
600 	d = enchant_broker_request_pwl_dict(pbroker->pbroker, (const char *)pwl);
601 	if (d) {
602 		pos = pbroker->dictcnt++;
603 		if (pbroker->dictcnt) {
604 			pbroker->dict = (enchant_dict **)erealloc(pbroker->dict, sizeof(enchant_dict *) * pbroker->dictcnt);
605 		} else {
606 			pbroker->dict = (enchant_dict **)emalloc(sizeof(enchant_dict *));
607 			pos = 0;
608 		}
609 
610 		dict = pbroker->dict[pos] = (enchant_dict *)emalloc(sizeof(enchant_dict));
611 		dict->id = pos;
612 		dict->pbroker = pbroker;
613 		dict->pdict = d;
614 		pbroker->dict[pos] = dict;
615 
616 		dict->rsrc = zend_register_resource(dict, le_enchant_dict);
617 		pbroker->rsrc->gc.refcount++;
618 		RETURN_RES(dict->rsrc);
619 	} else {
620 		RETURN_FALSE;
621 	}
622 }
623 /* }}} */
624 
625 /* {{{ proto resource enchant_broker_free_dict(resource dict)
626    Free the dictionary resource */
PHP_FUNCTION(enchant_broker_free_dict)627 PHP_FUNCTION(enchant_broker_free_dict)
628 {
629 	zval *dict;
630 	enchant_dict *pdict;
631 
632 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &dict) == FAILURE) {
633 		RETURN_FALSE;
634 	}
635 
636 	PHP_ENCHANT_GET_DICT;
637 
638 	zend_list_close(Z_RES_P(dict));
639 	RETURN_TRUE;
640 }
641 /* }}} */
642 
643 /* {{{ proto bool enchant_broker_dict_exists(resource broker, string tag)
644    Whether a dictionary exists or not. Using non-empty tag */
PHP_FUNCTION(enchant_broker_dict_exists)645 PHP_FUNCTION(enchant_broker_dict_exists)
646 {
647 	zval *broker;
648 	char *tag;
649 	size_t taglen;
650 	enchant_broker * pbroker;
651 
652 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &broker, &tag, &taglen) == FAILURE) {
653 		RETURN_FALSE;
654 	}
655 
656 	PHP_ENCHANT_GET_BROKER;
657 
658 	RETURN_BOOL(enchant_broker_dict_exists(pbroker->pbroker, tag));
659 }
660 /* }}} */
661 
662 /* {{{ proto bool enchant_broker_set_ordering(resource broker, string tag, string ordering)
663 	Declares a preference of dictionaries to use for the language
664 	described/referred to by 'tag'. The ordering is a comma delimited
665 	list of provider names. As a special exception, the "*" tag can
666 	be used as a language tag to declare a default ordering for any
667 	language that does not explicitly declare an ordering. */
668 
PHP_FUNCTION(enchant_broker_set_ordering)669 PHP_FUNCTION(enchant_broker_set_ordering)
670 {
671 	zval *broker;
672 	char *pordering;
673 	size_t porderinglen;
674 	char *ptag;
675 	size_t ptaglen;
676 	enchant_broker * pbroker;
677 
678 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rss", &broker, &ptag, &ptaglen, &pordering, &porderinglen) == FAILURE) {
679 		RETURN_FALSE;
680 	}
681 
682 	PHP_ENCHANT_GET_BROKER;
683 
684 	enchant_broker_set_ordering(pbroker->pbroker, ptag, pordering);
685 	RETURN_TRUE;
686 }
687 /* }}} */
688 
689 /* {{{ proto array enchant_broker_describe(resource broker)
690 	Enumerates the Enchant providers and tells you some rudimentary information about them. The same info is provided through phpinfo() */
PHP_FUNCTION(enchant_broker_describe)691 PHP_FUNCTION(enchant_broker_describe)
692 {
693 	EnchantBrokerDescribeFn describetozval = enumerate_providers_fn;
694 	zval *broker;
695 	enchant_broker * pbroker;
696 
697 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &broker) == FAILURE) {
698 		RETURN_FALSE;
699 	}
700 
701 	PHP_ENCHANT_GET_BROKER;
702 
703 	enchant_broker_describe(pbroker->pbroker, describetozval, (void *)return_value);
704 }
705 /* }}} */
706 
707 /* {{{ proto bool enchant_dict_quick_check(resource dict, string word [, array &suggestions])
708     If the word is correctly spelled return true, otherwise return false, if suggestions variable
709     is provided, fill it with spelling alternatives. */
PHP_FUNCTION(enchant_dict_quick_check)710 PHP_FUNCTION(enchant_dict_quick_check)
711 {
712 	zval *dict, *sugg = NULL;
713 	char *word;
714 	size_t wordlen;
715 	enchant_dict *pdict;
716 
717 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|z/", &dict, &word, &wordlen, &sugg) == FAILURE) {
718 		RETURN_FALSE;
719 	}
720 
721 	if (sugg) {
722 		zval_ptr_dtor(sugg);
723 		array_init(sugg);
724 	}
725 
726 	PHP_ENCHANT_GET_DICT;
727 
728 	if (enchant_dict_check(pdict->pdict, word, wordlen) > 0) {
729 		int n_sugg;
730 		size_t n_sugg_st;
731 		char **suggs;
732 
733 		if (!sugg && ZEND_NUM_ARGS() == 2) {
734 			RETURN_FALSE;
735 		}
736 
737 		suggs = enchant_dict_suggest(pdict->pdict, word, wordlen, &n_sugg_st);
738 		memcpy(&n_sugg, &n_sugg_st, sizeof(n_sugg));
739 		if (suggs && n_sugg) {
740 			int i;
741 			for (i = 0; i < n_sugg; i++) {
742 				add_next_index_string(sugg, suggs[i]);
743 			}
744 			enchant_dict_free_suggestions(pdict->pdict, suggs);
745 		}
746 
747 
748 		RETURN_FALSE;
749 	}
750 	RETURN_TRUE;
751 }
752 /* }}} */
753 
754 /* {{{ proto bool enchant_dict_check(resource dict, string word)
755     If the word is correctly spelled return true, otherwise return false */
PHP_FUNCTION(enchant_dict_check)756 PHP_FUNCTION(enchant_dict_check)
757 {
758 	zval *dict;
759 	char *word;
760 	size_t wordlen;
761 	enchant_dict *pdict;
762 
763 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &dict, &word, &wordlen) == FAILURE) {
764 		RETURN_FALSE;
765 	}
766 
767 	PHP_ENCHANT_GET_DICT;
768 
769 	RETURN_BOOL(!enchant_dict_check(pdict->pdict, word, wordlen));
770 }
771 /* }}} */
772 
773 /* {{{ proto array enchant_dict_suggest(resource dict, string word)
774     Will return a list of values if any of those pre-conditions are not met.*/
PHP_FUNCTION(enchant_dict_suggest)775 PHP_FUNCTION(enchant_dict_suggest)
776 {
777 	zval *dict;
778 	char *word;
779 	size_t wordlen;
780 	char **suggs;
781 	enchant_dict *pdict;
782 	int n_sugg;
783 	size_t n_sugg_st;
784 
785 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &dict, &word, &wordlen) == FAILURE) {
786 		RETURN_FALSE;
787 	}
788 
789 	PHP_ENCHANT_GET_DICT;
790 
791 	suggs = enchant_dict_suggest(pdict->pdict, word, wordlen, &n_sugg_st);
792 	memcpy(&n_sugg, &n_sugg_st, sizeof(n_sugg));
793 	if (suggs && n_sugg) {
794 		int i;
795 
796 		array_init(return_value);
797 		for (i = 0; i < n_sugg; i++) {
798 			add_next_index_string(return_value, suggs[i]);
799 		}
800 
801 		enchant_dict_free_suggestions(pdict->pdict, suggs);
802 	}
803 }
804 /* }}} */
805 
806 /* {{{ proto void enchant_dict_add_to_personal(resource dict, string word)
807      add 'word' to personal word list */
PHP_FUNCTION(enchant_dict_add_to_personal)808 PHP_FUNCTION(enchant_dict_add_to_personal)
809 {
810 	zval *dict;
811 	char *word;
812 	size_t wordlen;
813 	enchant_dict *pdict;
814 
815 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &dict, &word, &wordlen) == FAILURE) {
816 		RETURN_FALSE;
817 	}
818 
819 	PHP_ENCHANT_GET_DICT;
820 
821 	enchant_dict_add_to_personal(pdict->pdict, word, wordlen);
822 }
823 /* }}} */
824 
825 /* {{{ proto void enchant_dict_add_to_session(resource dict, string word)
826    add 'word' to this spell-checking session */
PHP_FUNCTION(enchant_dict_add_to_session)827 PHP_FUNCTION(enchant_dict_add_to_session)
828 {
829 	zval *dict;
830 	char *word;
831 	size_t wordlen;
832 	enchant_dict *pdict;
833 
834 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &dict, &word, &wordlen) == FAILURE) {
835 		RETURN_FALSE;
836 	}
837 
838 	PHP_ENCHANT_GET_DICT;
839 
840 	enchant_dict_add_to_session(pdict->pdict, word, wordlen);
841 }
842 /* }}} */
843 
844 /* {{{ proto bool enchant_dict_is_in_session(resource dict, string word)
845    whether or not 'word' exists in this spelling-session */
PHP_FUNCTION(enchant_dict_is_in_session)846 PHP_FUNCTION(enchant_dict_is_in_session)
847 {
848 	zval *dict;
849 	char *word;
850 	size_t wordlen;
851 	enchant_dict *pdict;
852 
853 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &dict, &word, &wordlen) == FAILURE) {
854 		RETURN_FALSE;
855 	}
856 
857 	PHP_ENCHANT_GET_DICT;
858 
859 	RETURN_BOOL(enchant_dict_is_in_session(pdict->pdict, word, wordlen));
860 }
861 /* }}} */
862 
863 /* {{{ proto void enchant_dict_store_replacement(resource dict, string mis, string cor)
864 	add a correction for 'mis' using 'cor'.
865 	Notes that you replaced @mis with @cor, so it's possibly more likely
866 	that future occurrences of @mis will be replaced with @cor. So it might
867 	bump @cor up in the suggestion list.*/
PHP_FUNCTION(enchant_dict_store_replacement)868 PHP_FUNCTION(enchant_dict_store_replacement)
869 {
870 	zval *dict;
871 	char *mis, *cor;
872 	size_t mislen, corlen;
873 
874 	enchant_dict *pdict;
875 
876 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rss", &dict, &mis, &mislen, &cor, &corlen) == FAILURE) {
877 		RETURN_FALSE;
878 	}
879 
880 	PHP_ENCHANT_GET_DICT;
881 
882 	enchant_dict_store_replacement(pdict->pdict, mis, mislen, cor, corlen);
883 }
884 /* }}} */
885 
886 /* {{{ proto string enchant_dict_get_error(resource dict)
887    Returns the last error of the current spelling-session */
PHP_FUNCTION(enchant_dict_get_error)888 PHP_FUNCTION(enchant_dict_get_error)
889 {
890 	zval *dict;
891 	enchant_dict *pdict;
892 	char *msg;
893 
894 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &dict) == FAILURE) {
895 		RETURN_FALSE;
896 	}
897 
898 	PHP_ENCHANT_GET_DICT;
899 
900 	msg = enchant_dict_get_error(pdict->pdict);
901 	if (msg) {
902 		RETURN_STRING((char *)msg);
903 	}
904 
905 	RETURN_FALSE;
906 }
907 /* }}} */
908 
909 /* {{{ proto array enchant_dict_describe(resource dict)
910    Describes an individual dictionary 'dict' */
PHP_FUNCTION(enchant_dict_describe)911 PHP_FUNCTION(enchant_dict_describe)
912 {
913 	zval *dict;
914 	enchant_dict *pdict;
915 
916 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &dict) == FAILURE) {
917 		RETURN_FALSE;
918 	}
919 
920 	PHP_ENCHANT_GET_DICT;
921 
922 	enchant_dict_describe(pdict->pdict, describe_dict_fn, (void *)return_value);
923 }
924 /* }}} */
925 
926 /*
927  * Local variables:
928  * tab-width: 4
929  * c-basic-offset: 4
930  * End:
931  * vim600: noet sw=4 ts=4 fdm=marker
932  * vim<600: noet sw=4 ts=4
933  */
934