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