pspell.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Author: Vlad Krupin <phpdevel@echospace.com> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifdef HAVE_CONFIG_H
  17. #include "config.h"
  18. #endif
  19. #include "php.h"
  20. #include <stdlib.h>
  21. #include <ctype.h>
  22. #include <stdio.h>
  23. #ifdef HAVE_PSPELL
  24. /* this will enforce compatibility in .12 version (broken after .11.2) */
  25. #define USE_ORIGINAL_MANAGER_FUNCS
  26. #include "php_pspell.h"
  27. #include <pspell.h>
  28. #include "ext/standard/info.h"
  29. #include "pspell_arginfo.h"
  30. #define PSPELL_FAST 1L
  31. #define PSPELL_NORMAL 2L
  32. #define PSPELL_BAD_SPELLERS 3L
  33. #define PSPELL_SPEED_MASK_INTERNAL 3L
  34. #define PSPELL_RUN_TOGETHER 8L
  35. /* Largest ignored word can be 999 characters (this seems sane enough),
  36. * and it takes 3 bytes to represent that (see pspell_config_ignore)
  37. */
  38. #define PSPELL_LARGEST_WORD 3
  39. static PHP_MINIT_FUNCTION(pspell);
  40. static PHP_MINFO_FUNCTION(pspell);
  41. static zend_class_entry *php_pspell_ce = NULL;
  42. static zend_object_handlers php_pspell_handlers;
  43. static zend_class_entry *php_pspell_config_ce = NULL;
  44. static zend_object_handlers php_pspell_config_handlers;
  45. zend_module_entry pspell_module_entry = {
  46. STANDARD_MODULE_HEADER,
  47. "pspell",
  48. ext_functions,
  49. PHP_MINIT(pspell),
  50. NULL,
  51. NULL,
  52. NULL,
  53. PHP_MINFO(pspell),
  54. PHP_PSPELL_VERSION,
  55. STANDARD_MODULE_PROPERTIES,
  56. };
  57. #ifdef COMPILE_DL_PSPELL
  58. ZEND_GET_MODULE(pspell)
  59. #endif
  60. /* class PSpell */
  61. typedef struct _php_pspell_object {
  62. PspellManager *mgr;
  63. zend_object std;
  64. } php_pspell_object;
  65. static php_pspell_object *php_pspell_object_from_zend_object(zend_object *zobj) {
  66. return ((php_pspell_object*)(zobj + 1)) - 1;
  67. }
  68. static zend_object *php_pspell_object_to_zend_object(php_pspell_object *obj) {
  69. return ((zend_object*)(obj + 1)) - 1;
  70. }
  71. static zend_function *php_pspell_object_get_constructor(zend_object *object)
  72. {
  73. zend_throw_error(NULL, "You cannot initialize a PSpell\\Dictionary object except through helper functions");
  74. return NULL;
  75. }
  76. static zend_object *php_pspell_object_create(zend_class_entry *ce)
  77. {
  78. php_pspell_object *obj = zend_object_alloc(sizeof(php_pspell_object), ce);
  79. zend_object *zobj = php_pspell_object_to_zend_object(obj);
  80. obj->mgr = NULL;
  81. zend_object_std_init(zobj, ce);
  82. object_properties_init(zobj, ce);
  83. zobj->handlers = &php_pspell_handlers;
  84. return zobj;
  85. }
  86. static void php_pspell_object_free(zend_object *zobj) {
  87. delete_pspell_manager(php_pspell_object_from_zend_object(zobj)->mgr);
  88. }
  89. /* class PSpellConfig */
  90. typedef struct _php_pspell_config_object {
  91. PspellConfig *cfg;
  92. zend_object std;
  93. } php_pspell_config_object;
  94. static php_pspell_config_object *php_pspell_config_object_from_zend_object(zend_object *zobj) {
  95. return ((php_pspell_config_object*)(zobj + 1)) - 1;
  96. }
  97. static zend_object *php_pspell_config_object_to_zend_object(php_pspell_config_object *obj) {
  98. return ((zend_object*)(obj + 1)) - 1;
  99. }
  100. static zend_function *php_pspell_config_object_get_constructor(zend_object *object)
  101. {
  102. zend_throw_error(NULL, "You cannot initialize a PSpell\\Config object except through helper functions");
  103. return NULL;
  104. }
  105. static zend_object *php_pspell_config_object_create(zend_class_entry *ce)
  106. {
  107. php_pspell_config_object *obj = zend_object_alloc(sizeof(php_pspell_config_object), ce);
  108. zend_object *zobj = php_pspell_config_object_to_zend_object(obj);
  109. obj->cfg = NULL;
  110. zend_object_std_init(zobj, ce);
  111. object_properties_init(zobj, ce);
  112. zobj->handlers = &php_pspell_config_handlers;
  113. return zobj;
  114. }
  115. static void php_pspell_config_object_free(zend_object *zobj) {
  116. delete_pspell_config(php_pspell_config_object_from_zend_object(zobj)->cfg);
  117. }
  118. /* {{{ PHP_MINIT_FUNCTION */
  119. static PHP_MINIT_FUNCTION(pspell)
  120. {
  121. php_pspell_ce = register_class_PSpell_Dictionary();
  122. php_pspell_ce->create_object = php_pspell_object_create;
  123. memcpy(&php_pspell_handlers, &std_object_handlers, sizeof(zend_object_handlers));
  124. php_pspell_handlers.clone_obj = NULL;
  125. php_pspell_handlers.free_obj = php_pspell_object_free;
  126. php_pspell_handlers.get_constructor = php_pspell_object_get_constructor;
  127. php_pspell_handlers.offset = XtOffsetOf(php_pspell_object, std);
  128. php_pspell_config_ce = register_class_PSpell_Config();
  129. php_pspell_config_ce->create_object = php_pspell_config_object_create;
  130. memcpy(&php_pspell_config_handlers, &std_object_handlers, sizeof(zend_object_handlers));
  131. php_pspell_config_handlers.clone_obj = NULL;
  132. php_pspell_config_handlers.free_obj = php_pspell_config_object_free;
  133. php_pspell_config_handlers.get_constructor = php_pspell_config_object_get_constructor;
  134. php_pspell_config_handlers.offset = XtOffsetOf(php_pspell_config_object, std);
  135. REGISTER_LONG_CONSTANT("PSPELL_FAST", PSPELL_FAST, CONST_PERSISTENT | CONST_CS);
  136. REGISTER_LONG_CONSTANT("PSPELL_NORMAL", PSPELL_NORMAL, CONST_PERSISTENT | CONST_CS);
  137. REGISTER_LONG_CONSTANT("PSPELL_BAD_SPELLERS", PSPELL_BAD_SPELLERS, CONST_PERSISTENT | CONST_CS);
  138. REGISTER_LONG_CONSTANT("PSPELL_RUN_TOGETHER", PSPELL_RUN_TOGETHER, CONST_PERSISTENT | CONST_CS);
  139. return SUCCESS;
  140. }
  141. /* }}} */
  142. /* {{{ Load a dictionary */
  143. PHP_FUNCTION(pspell_new)
  144. {
  145. char *language, *spelling = NULL, *jargon = NULL, *encoding = NULL;
  146. size_t language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0;
  147. zend_long mode = Z_L(0), speed = Z_L(0);
  148. int argc = ZEND_NUM_ARGS();
  149. #ifdef PHP_WIN32
  150. TCHAR aspell_dir[200];
  151. TCHAR data_dir[220];
  152. TCHAR dict_dir[220];
  153. HKEY hkey;
  154. DWORD dwType,dwLen;
  155. #endif
  156. PspellCanHaveError *ret;
  157. PspellConfig *config;
  158. if (zend_parse_parameters(argc, "s|sssl", &language, &language_len, &spelling, &spelling_len,
  159. &jargon, &jargon_len, &encoding, &encoding_len, &mode) == FAILURE) {
  160. RETURN_THROWS();
  161. }
  162. config = new_pspell_config();
  163. #ifdef PHP_WIN32
  164. /* If aspell was installed using installer, we should have a key
  165. * pointing to the location of the dictionaries
  166. */
  167. if (0 == RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Aspell", &hkey)) {
  168. LONG result;
  169. dwLen = sizeof(aspell_dir) - 1;
  170. result = RegQueryValueEx(hkey, "", NULL, &dwType, (LPBYTE)&aspell_dir, &dwLen);
  171. RegCloseKey(hkey);
  172. if (result == ERROR_SUCCESS) {
  173. strlcpy(data_dir, aspell_dir, sizeof(data_dir));
  174. strlcat(data_dir, "\\data", sizeof(data_dir));
  175. strlcpy(dict_dir, aspell_dir, sizeof(dict_dir));
  176. strlcat(dict_dir, "\\dict", sizeof(dict_dir));
  177. pspell_config_replace(config, "data-dir", data_dir);
  178. pspell_config_replace(config, "dict-dir", dict_dir);
  179. }
  180. }
  181. #endif
  182. pspell_config_replace(config, "language-tag", language);
  183. if (spelling_len) {
  184. pspell_config_replace(config, "spelling", spelling);
  185. }
  186. if (jargon_len) {
  187. pspell_config_replace(config, "jargon", jargon);
  188. }
  189. if (encoding_len) {
  190. pspell_config_replace(config, "encoding", encoding);
  191. }
  192. if (mode) {
  193. speed = mode & PSPELL_SPEED_MASK_INTERNAL;
  194. /* First check what mode we want (how many suggestions) */
  195. if (speed == PSPELL_FAST) {
  196. pspell_config_replace(config, "sug-mode", "fast");
  197. } else if (speed == PSPELL_NORMAL) {
  198. pspell_config_replace(config, "sug-mode", "normal");
  199. } else if (speed == PSPELL_BAD_SPELLERS) {
  200. pspell_config_replace(config, "sug-mode", "bad-spellers");
  201. }
  202. /* Then we see if run-together words should be treated as valid components */
  203. if (mode & PSPELL_RUN_TOGETHER) {
  204. pspell_config_replace(config, "run-together", "true");
  205. }
  206. }
  207. ret = new_pspell_manager(config);
  208. delete_pspell_config(config);
  209. if (pspell_error_number(ret) != 0) {
  210. php_error_docref(NULL, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret));
  211. delete_pspell_can_have_error(ret);
  212. RETURN_FALSE;
  213. }
  214. object_init_ex(return_value, php_pspell_ce);
  215. php_pspell_object_from_zend_object(Z_OBJ_P(return_value))->mgr = to_pspell_manager(ret);
  216. }
  217. /* }}} */
  218. /* {{{ Load a dictionary with a personal wordlist*/
  219. PHP_FUNCTION(pspell_new_personal)
  220. {
  221. char *personal, *language, *spelling = NULL, *jargon = NULL, *encoding = NULL;
  222. size_t personal_len, language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0;
  223. zend_long mode = Z_L(0), speed = Z_L(0);
  224. int argc = ZEND_NUM_ARGS();
  225. #ifdef PHP_WIN32
  226. TCHAR aspell_dir[200];
  227. TCHAR data_dir[220];
  228. TCHAR dict_dir[220];
  229. HKEY hkey;
  230. DWORD dwType,dwLen;
  231. #endif
  232. PspellCanHaveError *ret;
  233. PspellConfig *config;
  234. if (zend_parse_parameters(argc, "ps|sssl", &personal, &personal_len, &language, &language_len,
  235. &spelling, &spelling_len, &jargon, &jargon_len, &encoding, &encoding_len, &mode) == FAILURE) {
  236. RETURN_THROWS();
  237. }
  238. config = new_pspell_config();
  239. #ifdef PHP_WIN32
  240. /* If aspell was installed using installer, we should have a key
  241. * pointing to the location of the dictionaries
  242. */
  243. if (0 == RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Aspell", &hkey)) {
  244. LONG result;
  245. dwLen = sizeof(aspell_dir) - 1;
  246. result = RegQueryValueEx(hkey, "", NULL, &dwType, (LPBYTE)&aspell_dir, &dwLen);
  247. RegCloseKey(hkey);
  248. if (result == ERROR_SUCCESS) {
  249. strlcpy(data_dir, aspell_dir, sizeof(data_dir));
  250. strlcat(data_dir, "\\data", sizeof(data_dir));
  251. strlcpy(dict_dir, aspell_dir, sizeof(dict_dir));
  252. strlcat(dict_dir, "\\dict", sizeof(dict_dir));
  253. pspell_config_replace(config, "data-dir", data_dir);
  254. pspell_config_replace(config, "dict-dir", dict_dir);
  255. }
  256. }
  257. #endif
  258. if (php_check_open_basedir(personal)) {
  259. delete_pspell_config(config);
  260. RETURN_FALSE;
  261. }
  262. pspell_config_replace(config, "personal", personal);
  263. pspell_config_replace(config, "save-repl", "false");
  264. pspell_config_replace(config, "language-tag", language);
  265. if (spelling_len) {
  266. pspell_config_replace(config, "spelling", spelling);
  267. }
  268. if (jargon_len) {
  269. pspell_config_replace(config, "jargon", jargon);
  270. }
  271. if (encoding_len) {
  272. pspell_config_replace(config, "encoding", encoding);
  273. }
  274. if (mode) {
  275. speed = mode & PSPELL_SPEED_MASK_INTERNAL;
  276. /* First check what mode we want (how many suggestions) */
  277. if (speed == PSPELL_FAST) {
  278. pspell_config_replace(config, "sug-mode", "fast");
  279. } else if (speed == PSPELL_NORMAL) {
  280. pspell_config_replace(config, "sug-mode", "normal");
  281. } else if (speed == PSPELL_BAD_SPELLERS) {
  282. pspell_config_replace(config, "sug-mode", "bad-spellers");
  283. }
  284. /* Then we see if run-together words should be treated as valid components */
  285. if (mode & PSPELL_RUN_TOGETHER) {
  286. pspell_config_replace(config, "run-together", "true");
  287. }
  288. }
  289. ret = new_pspell_manager(config);
  290. delete_pspell_config(config);
  291. if (pspell_error_number(ret) != 0) {
  292. php_error_docref(NULL, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret));
  293. delete_pspell_can_have_error(ret);
  294. RETURN_FALSE;
  295. }
  296. object_init_ex(return_value, php_pspell_ce);
  297. php_pspell_object_from_zend_object(Z_OBJ_P(return_value))->mgr = to_pspell_manager(ret);
  298. }
  299. /* }}} */
  300. /* {{{ Load a dictionary based on the given config */
  301. PHP_FUNCTION(pspell_new_config)
  302. {
  303. zval *zcfg;
  304. PspellCanHaveError *ret;
  305. PspellConfig *config;
  306. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zcfg, php_pspell_config_ce) == FAILURE) {
  307. RETURN_THROWS();
  308. }
  309. config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg;
  310. ret = new_pspell_manager(config);
  311. if (pspell_error_number(ret) != 0) {
  312. php_error_docref(NULL, E_WARNING, "PSPELL couldn't open the dictionary. reason: %s", pspell_error_message(ret));
  313. delete_pspell_can_have_error(ret);
  314. RETURN_FALSE;
  315. }
  316. object_init_ex(return_value, php_pspell_ce);
  317. php_pspell_object_from_zend_object(Z_OBJ_P(return_value))->mgr = to_pspell_manager(ret);
  318. }
  319. /* }}} */
  320. /* {{{ Returns true if word is valid */
  321. PHP_FUNCTION(pspell_check)
  322. {
  323. zval *zmgr;
  324. zend_string *word;
  325. PspellManager *manager;
  326. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS", &zmgr, php_pspell_ce, &word) == FAILURE) {
  327. RETURN_THROWS();
  328. }
  329. manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr;
  330. if (pspell_manager_check(manager, ZSTR_VAL(word))) {
  331. RETURN_TRUE;
  332. } else {
  333. RETURN_FALSE;
  334. }
  335. }
  336. /* }}} */
  337. /* {{{ Returns array of suggestions */
  338. PHP_FUNCTION(pspell_suggest)
  339. {
  340. zval *zmgr;
  341. zend_string *word;
  342. PspellManager *manager;
  343. const PspellWordList *wl;
  344. const char *sug;
  345. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS", &zmgr, php_pspell_ce, &word) == FAILURE) {
  346. RETURN_THROWS();
  347. }
  348. manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr;
  349. array_init(return_value);
  350. wl = pspell_manager_suggest(manager, ZSTR_VAL(word));
  351. if (wl) {
  352. PspellStringEmulation *els = pspell_word_list_elements(wl);
  353. while ((sug = pspell_string_emulation_next(els)) != 0) {
  354. add_next_index_string(return_value,(char *)sug);
  355. }
  356. delete_pspell_string_emulation(els);
  357. } else {
  358. php_error_docref(NULL, E_WARNING, "PSPELL had a problem. details: %s", pspell_manager_error_message(manager));
  359. RETURN_FALSE;
  360. }
  361. }
  362. /* }}} */
  363. /* {{{ Notify the dictionary of a user-selected replacement */
  364. PHP_FUNCTION(pspell_store_replacement)
  365. {
  366. zval *zmgr;
  367. zend_string *miss, *corr;
  368. PspellManager *manager;
  369. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OSS", &zmgr, php_pspell_ce, &miss, &corr) == FAILURE) {
  370. RETURN_THROWS();
  371. }
  372. manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr;
  373. pspell_manager_store_replacement(manager, ZSTR_VAL(miss), ZSTR_VAL(corr));
  374. if (pspell_manager_error_number(manager) == 0) {
  375. RETURN_TRUE;
  376. } else {
  377. php_error_docref(NULL, E_WARNING, "pspell_store_replacement() gave error: %s", pspell_manager_error_message(manager));
  378. RETURN_FALSE;
  379. }
  380. }
  381. /* }}} */
  382. /* {{{ Adds a word to a personal list */
  383. PHP_FUNCTION(pspell_add_to_personal)
  384. {
  385. zval *zmgr;
  386. zend_string *word;
  387. PspellManager *manager;
  388. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS", &zmgr, php_pspell_ce, &word) == FAILURE) {
  389. RETURN_THROWS();
  390. }
  391. manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr;
  392. /*If the word is empty, we have to return; otherwise we'll segfault! ouch!*/
  393. if (ZSTR_LEN(word) == 0) {
  394. RETURN_FALSE;
  395. }
  396. pspell_manager_add_to_personal(manager, ZSTR_VAL(word));
  397. if (pspell_manager_error_number(manager) == 0) {
  398. RETURN_TRUE;
  399. } else {
  400. php_error_docref(NULL, E_WARNING, "pspell_add_to_personal() gave error: %s", pspell_manager_error_message(manager));
  401. RETURN_FALSE;
  402. }
  403. }
  404. /* }}} */
  405. /* {{{ Adds a word to the current session */
  406. PHP_FUNCTION(pspell_add_to_session)
  407. {
  408. zval *zmgr;
  409. zend_string *word;
  410. PspellManager *manager;
  411. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS", &zmgr, php_pspell_ce, &word) == FAILURE) {
  412. RETURN_THROWS();
  413. }
  414. manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr;
  415. /*If the word is empty, we have to return; otherwise we'll segfault! ouch!*/
  416. if (ZSTR_LEN(word) == 0) {
  417. RETURN_FALSE;
  418. }
  419. pspell_manager_add_to_session(manager, ZSTR_VAL(word));
  420. if (pspell_manager_error_number(manager) == 0) {
  421. RETURN_TRUE;
  422. } else {
  423. php_error_docref(NULL, E_WARNING, "pspell_add_to_session() gave error: %s", pspell_manager_error_message(manager));
  424. RETURN_FALSE;
  425. }
  426. }
  427. /* }}} */
  428. /* {{{ Clears the current session */
  429. PHP_FUNCTION(pspell_clear_session)
  430. {
  431. zval *zmgr;
  432. PspellManager *manager;
  433. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zmgr, php_pspell_ce) == FAILURE) {
  434. RETURN_THROWS();
  435. }
  436. manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr;
  437. pspell_manager_clear_session(manager);
  438. if (pspell_manager_error_number(manager) == 0) {
  439. RETURN_TRUE;
  440. } else {
  441. php_error_docref(NULL, E_WARNING, "pspell_clear_session() gave error: %s", pspell_manager_error_message(manager));
  442. RETURN_FALSE;
  443. }
  444. }
  445. /* }}} */
  446. /* {{{ Saves the current (personal) wordlist */
  447. PHP_FUNCTION(pspell_save_wordlist)
  448. {
  449. zval *zmgr;
  450. PspellManager *manager;
  451. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zmgr, php_pspell_ce) == FAILURE) {
  452. RETURN_THROWS();
  453. }
  454. manager = php_pspell_object_from_zend_object(Z_OBJ_P(zmgr))->mgr;
  455. pspell_manager_save_all_word_lists(manager);
  456. if (pspell_manager_error_number(manager) == 0) {
  457. RETURN_TRUE;
  458. } else {
  459. php_error_docref(NULL, E_WARNING, "pspell_save_wordlist() gave error: %s", pspell_manager_error_message(manager));
  460. RETURN_FALSE;
  461. }
  462. }
  463. /* }}} */
  464. /* {{{ Create a new config to be used later to create a manager */
  465. PHP_FUNCTION(pspell_config_create)
  466. {
  467. char *language, *spelling = NULL, *jargon = NULL, *encoding = NULL;
  468. size_t language_len, spelling_len = 0, jargon_len = 0, encoding_len = 0;
  469. PspellConfig *config;
  470. #ifdef PHP_WIN32
  471. TCHAR aspell_dir[200];
  472. TCHAR data_dir[220];
  473. TCHAR dict_dir[220];
  474. HKEY hkey;
  475. DWORD dwType,dwLen;
  476. #endif
  477. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|sss", &language, &language_len, &spelling, &spelling_len,
  478. &jargon, &jargon_len, &encoding, &encoding_len) == FAILURE) {
  479. RETURN_THROWS();
  480. }
  481. config = new_pspell_config();
  482. #ifdef PHP_WIN32
  483. /* If aspell was installed using installer, we should have a key
  484. * pointing to the location of the dictionaries
  485. */
  486. if (0 == RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Aspell", &hkey)) {
  487. LONG result;
  488. dwLen = sizeof(aspell_dir) - 1;
  489. result = RegQueryValueEx(hkey, "", NULL, &dwType, (LPBYTE)&aspell_dir, &dwLen);
  490. RegCloseKey(hkey);
  491. if (result == ERROR_SUCCESS) {
  492. strlcpy(data_dir, aspell_dir, sizeof(data_dir));
  493. strlcat(data_dir, "\\data", sizeof(data_dir));
  494. strlcpy(dict_dir, aspell_dir, sizeof(dict_dir));
  495. strlcat(dict_dir, "\\dict", sizeof(dict_dir));
  496. pspell_config_replace(config, "data-dir", data_dir);
  497. pspell_config_replace(config, "dict-dir", dict_dir);
  498. }
  499. }
  500. #endif
  501. pspell_config_replace(config, "language-tag", language);
  502. if (spelling_len) {
  503. pspell_config_replace(config, "spelling", spelling);
  504. }
  505. if (jargon_len) {
  506. pspell_config_replace(config, "jargon", jargon);
  507. }
  508. if (encoding_len) {
  509. pspell_config_replace(config, "encoding", encoding);
  510. }
  511. /* By default I do not want to write anything anywhere because it'll try to write to $HOME
  512. which is not what we want */
  513. pspell_config_replace(config, "save-repl", "false");
  514. object_init_ex(return_value, php_pspell_config_ce);
  515. php_pspell_config_object_from_zend_object(Z_OBJ_P(return_value))->cfg = config;
  516. }
  517. /* }}} */
  518. /* {{{ Consider run-together words as valid components */
  519. PHP_FUNCTION(pspell_config_runtogether)
  520. {
  521. zval *zcfg;
  522. bool runtogether;
  523. PspellConfig *config;
  524. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ob", &zcfg, php_pspell_config_ce, &runtogether) == FAILURE) {
  525. RETURN_THROWS();
  526. }
  527. config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg;
  528. pspell_config_replace(config, "run-together", runtogether ? "true" : "false");
  529. RETURN_TRUE;
  530. }
  531. /* }}} */
  532. /* {{{ Select mode for config (PSPELL_FAST, PSPELL_NORMAL or PSPELL_BAD_SPELLERS) */
  533. PHP_FUNCTION(pspell_config_mode)
  534. {
  535. zval *zcfg;
  536. zend_long mode;
  537. PspellConfig *config;
  538. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &zcfg, php_pspell_config_ce, &mode) == FAILURE) {
  539. RETURN_THROWS();
  540. }
  541. config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg;
  542. /* First check what mode we want (how many suggestions) */
  543. if (mode == PSPELL_FAST) {
  544. pspell_config_replace(config, "sug-mode", "fast");
  545. } else if (mode == PSPELL_NORMAL) {
  546. pspell_config_replace(config, "sug-mode", "normal");
  547. } else if (mode == PSPELL_BAD_SPELLERS) {
  548. pspell_config_replace(config, "sug-mode", "bad-spellers");
  549. }
  550. RETURN_TRUE;
  551. }
  552. /* }}} */
  553. /* {{{ Ignore words <= n chars */
  554. PHP_FUNCTION(pspell_config_ignore)
  555. {
  556. char ignore_str[MAX_LENGTH_OF_LONG + 1];
  557. zval *zcfg;
  558. zend_long ignore = 0L;
  559. PspellConfig *config;
  560. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &zcfg, php_pspell_config_ce, &ignore) == FAILURE) {
  561. RETURN_THROWS();
  562. }
  563. config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg;
  564. snprintf(ignore_str, sizeof(ignore_str), ZEND_LONG_FMT, ignore);
  565. pspell_config_replace(config, "ignore", ignore_str);
  566. RETURN_TRUE;
  567. }
  568. /* }}} */
  569. static void pspell_config_path(INTERNAL_FUNCTION_PARAMETERS, char *option)
  570. {
  571. zval *zcfg;
  572. zend_string *value;
  573. PspellConfig *config;
  574. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OP", &zcfg, php_pspell_config_ce, &value) == FAILURE) {
  575. RETURN_THROWS();
  576. }
  577. config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg;
  578. if (php_check_open_basedir(ZSTR_VAL(value))) {
  579. RETURN_FALSE;
  580. }
  581. pspell_config_replace(config, option, ZSTR_VAL(value));
  582. RETURN_TRUE;
  583. }
  584. /* {{{ Use a personal dictionary for this config */
  585. PHP_FUNCTION(pspell_config_personal)
  586. {
  587. pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "personal");
  588. }
  589. /* }}} */
  590. /* {{{ location of the main word list */
  591. PHP_FUNCTION(pspell_config_dict_dir)
  592. {
  593. pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "dict-dir");
  594. }
  595. /* }}} */
  596. /* {{{ location of language data files */
  597. PHP_FUNCTION(pspell_config_data_dir)
  598. {
  599. pspell_config_path(INTERNAL_FUNCTION_PARAM_PASSTHRU, "data-dir");
  600. }
  601. /* }}} */
  602. /* {{{ Use a personal dictionary with replacement pairs for this config */
  603. PHP_FUNCTION(pspell_config_repl)
  604. {
  605. zval *zcfg;
  606. zend_string *repl;
  607. PspellConfig *config;
  608. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OP", &zcfg, php_pspell_config_ce, &repl) == FAILURE) {
  609. RETURN_THROWS();
  610. }
  611. config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg;
  612. pspell_config_replace(config, "save-repl", "true");
  613. if (php_check_open_basedir(ZSTR_VAL(repl))) {
  614. RETURN_FALSE;
  615. }
  616. pspell_config_replace(config, "repl", ZSTR_VAL(repl));
  617. RETURN_TRUE;
  618. }
  619. /* }}} */
  620. /* {{{ Save replacement pairs when personal list is saved for this config */
  621. PHP_FUNCTION(pspell_config_save_repl)
  622. {
  623. zval *zcfg;
  624. bool save;
  625. PspellConfig *config;
  626. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ob", &zcfg, php_pspell_config_ce, &save) == FAILURE) {
  627. RETURN_THROWS();
  628. }
  629. config = php_pspell_config_object_from_zend_object(Z_OBJ_P(zcfg))->cfg;
  630. pspell_config_replace(config, "save-repl", save ? "true" : "false");
  631. RETURN_TRUE;
  632. }
  633. /* }}} */
  634. /* {{{ PHP_MINFO_FUNCTION */
  635. static PHP_MINFO_FUNCTION(pspell)
  636. {
  637. php_info_print_table_start();
  638. php_info_print_table_row(2, "PSpell Support", "enabled");
  639. php_info_print_table_end();
  640. }
  641. /* }}} */
  642. #endif