RPA Toolkit
added rpaparse
[rpatk.git] / phpext / prpa / prpa.c
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2008 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.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:                                                              |
16   +----------------------------------------------------------------------+
17 */
18
19 /* $Id: header,v 1.16.2.1.2.1.2.1 2008/02/07 19:39:50 iliaa Exp $ */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "php.h"
26 #include "php_ini.h"
27 #include "ext/standard/info.h"
28 #include "php_prpa.h"
29 #include "TSRM/TSRM.h"
30 #include "rpadbex.h"
31 #include "rpastat.h"
32 #include "rpastatpriv.h"
33 #include "rpaerror.h"
34 #include "rparecord.h"
35
36 typedef struct _php_rpa_dbex {
37         rpadbex_t* hDbex;
38         zval *zinput;
39 #ifdef ZTS
40         TSRMLS_D;       
41 #endif
42 } php_rpa_dbex;
43
44 #define PHP_RPA_DBEX_RES_NAME "php rpa dbex"
45
46
47 typedef struct _php_rpa_stat {
48         rpastat_t* stat;
49         zval *zinput;
50 #ifdef ZTS
51         TSRMLS_D;
52 #endif
53 } php_rpa_stat;
54
55 #define PHP_RPA_STAT_RES_NAME "php rpa stat"
56
57
58 typedef struct _php_rpa_records {
59         rarray_t* records;
60 #ifdef ZTS
61         TSRMLS_D;
62 #endif
63 } php_rpa_records;
64
65 #define PHP_RPA_RECORDS_RES_NAME "php rpa records"
66
67
68 static int le_rpa;
69 static int le_rpa_dbex;
70 static int le_rpa_stat;
71 //static int le_rpa_records;
72 static void php_rpa_dbex_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC);
73 static void php_rpa_stat_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC);
74 static void php_rpa_records_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC);
75
76
77 /* If you declare any globals in php_prpa.h uncomment this:
78 ZEND_DECLARE_MODULE_GLOBALS(prpa)
79 */
80
81 /* True global resources - no need for thread safety here */
82 static int le_prpa;
83
84 /* {{{ prpa_functions[]
85  *
86  * Every user visible function must have an entry in prpa_functions[].
87  */
88 zend_function_entry prpa_functions[] = {
89     PHP_FE(rpaparse, NULL)
90     PHP_FE(rpa_dbex_version, NULL)
91     PHP_FE(rpa_dbex_create, NULL)
92     PHP_FE(rpa_dbex_open, NULL)
93     PHP_FE(rpa_dbex_close, NULL)
94     PHP_FE(rpa_dbex_load, NULL)
95     PHP_FE(rpa_dbex_compile, NULL)
96     PHP_FE(rpa_dbex_lookup, NULL)
97     PHP_FE(rpa_dbex_first, NULL)
98     PHP_FE(rpa_dbex_last, NULL)
99     PHP_FE(rpa_dbex_cfgset, NULL)
100     PHP_FE(rpa_dbex_dumpproductions, NULL)
101     PHP_FE(rpa_stat_create, NULL)
102     PHP_FE(rpa_stat_match, NULL)
103     PHP_FE(rpa_stat_scan, NULL)
104     PHP_FE(rpa_stat_parse, NULL)
105
106
107 #if 0
108     PHP_FE(rpa_records_create, NULL)
109     PHP_FE(rpa_records_length, NULL)
110     PHP_FE(rpa_records_get, NULL)
111
112     PHP_FE(rpa_dbex_strmatch, NULL)
113     PHP_FE(rpa_dbex_set_encoding, NULL)
114     PHP_FE(rpa_dbex_match, NULL)
115     PHP_FE(rpa_dbex_parse, NULL)
116     PHP_FE(rpa_dbex_scan, NULL)
117     PHP_FE(rpa_dbex_get_pattern, NULL)
118     PHP_FE(rpa_dbex_default_pattern, NULL)
119     PHP_FE(rpa_dbex_first_pattern, NULL)
120     PHP_FE(rpa_dbex_last_pattern, NULL)
121     PHP_FE(rpa_dbex_next_pattern, NULL)
122     PHP_FE(rpa_dbex_prev_pattern, NULL)
123     PHP_FE(rpa_dbex_pattern_name, NULL)
124     PHP_FE(rpa_dbex_pattern_regex, NULL)
125     PHP_FE(rpa_dbex_add_callback, NULL)
126 #endif
127         {NULL, NULL, NULL}      /* Must be the last line in prpa_functions[] */
128 };
129 /* }}} */
130
131 /* {{{ prpa_module_entry
132  */
133 zend_module_entry prpa_module_entry = {
134 #if ZEND_MODULE_API_NO >= 20010901
135         STANDARD_MODULE_HEADER,
136 #endif
137         "prpa",
138         prpa_functions,
139         PHP_MINIT(prpa),
140         PHP_MSHUTDOWN(prpa),
141         PHP_RINIT(prpa),                /* Replace with NULL if there's nothing to do at request start */
142         PHP_RSHUTDOWN(prpa),    /* Replace with NULL if there's nothing to do at request end */
143         PHP_MINFO(prpa),
144 #if ZEND_MODULE_API_NO >= 20010901
145         "0.1", /* Replace with version number for your extension */
146 #endif
147         STANDARD_MODULE_PROPERTIES
148 };
149 /* }}} */
150
151 #ifdef COMPILE_DL_PRPA
152 ZEND_GET_MODULE(prpa)
153 #endif
154
155 /* {{{ PHP_INI
156  */
157 /* Remove comments and fill if you need to have entries in php.ini
158 PHP_INI_BEGIN()
159     STD_PHP_INI_ENTRY("prpa.global_value",      "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_prpa_globals, prpa_globals)
160     STD_PHP_INI_ENTRY("prpa.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_prpa_globals, prpa_globals)
161 PHP_INI_END()
162 */
163 /* }}} */
164
165 /* {{{ php_prpa_init_globals
166  */
167 /* Uncomment this function if you have INI entries
168 static void php_prpa_init_globals(zend_prpa_globals *prpa_globals)
169 {
170         prpa_globals->global_value = 0;
171         prpa_globals->global_string = NULL;
172 }
173 */
174 /* }}} */
175
176 /* {{{ PHP_MINIT_FUNCTION
177  */
178 PHP_MINIT_FUNCTION(prpa)
179 {
180         /* If you have INI entries, uncomment these lines 
181         REGISTER_INI_ENTRIES();
182         */
183     le_rpa_dbex = zend_register_list_destructors_ex(php_rpa_dbex_dtor, NULL, PHP_RPA_DBEX_RES_NAME, module_number);
184     le_rpa_stat = zend_register_list_destructors_ex(php_rpa_stat_dtor, NULL, PHP_RPA_STAT_RES_NAME, module_number);
185 //    le_rpa_records = zend_register_list_destructors_ex(php_rpa_records_dtor, NULL, PHP_RPA_RECORDS_RES_NAME, module_number);
186
187     REGISTER_LONG_CONSTANT("RPA_ENCODING_BYTE", RPA_ENCODING_BYTE, CONST_CS | CONST_PERSISTENT);
188     REGISTER_LONG_CONSTANT("RPA_ENCODING_UTF8", RPA_ENCODING_UTF8, CONST_CS | CONST_PERSISTENT);
189     REGISTER_LONG_CONSTANT("RPA_ENCODING_ICASE_UTF8", RPA_ENCODING_ICASE_UTF8, CONST_CS | CONST_PERSISTENT);
190     REGISTER_LONG_CONSTANT("RPA_ENCODING_UTF16LE", RPA_ENCODING_UTF16LE, CONST_CS | CONST_PERSISTENT);
191     REGISTER_LONG_CONSTANT("RPA_ENCODING_ICASE_UTF16LE", RPA_ENCODING_ICASE_UTF16LE, CONST_CS | CONST_PERSISTENT);
192     REGISTER_LONG_CONSTANT("RPA_RECORD_START", RPA_RECORD_START, CONST_CS | CONST_PERSISTENT);
193     REGISTER_LONG_CONSTANT("RPA_RECORD_END", RPA_RECORD_END, CONST_CS | CONST_PERSISTENT);
194     REGISTER_LONG_CONSTANT("RPA_DBEXCFG_DEBUG", RPA_DBEXCFG_DEBUG, CONST_CS | CONST_PERSISTENT);
195     REGISTER_LONG_CONSTANT("RPA_DBEXCFG_OPTIMIZATIONS", RPA_DBEXCFG_OPTIMIZATIONS, CONST_CS | CONST_PERSISTENT);
196
197         return SUCCESS;
198 }
199 /* }}} */
200
201 /* {{{ PHP_MSHUTDOWN_FUNCTION
202  */
203 PHP_MSHUTDOWN_FUNCTION(prpa)
204 {
205         /* uncomment this line if you have INI entries
206         UNREGISTER_INI_ENTRIES();
207         */
208         return SUCCESS;
209 }
210 /* }}} */
211
212 /* Remove if there's nothing to do at request start */
213 /* {{{ PHP_RINIT_FUNCTION
214  */
215 PHP_RINIT_FUNCTION(prpa)
216 {
217         return SUCCESS;
218 }
219 /* }}} */
220
221 /* Remove if there's nothing to do at request end */
222 /* {{{ PHP_RSHUTDOWN_FUNCTION
223  */
224 PHP_RSHUTDOWN_FUNCTION(prpa)
225 {
226         return SUCCESS;
227 }
228 /* }}} */
229
230 /* {{{ PHP_MINFO_FUNCTION
231  */
232 PHP_MINFO_FUNCTION(prpa)
233 {
234         php_info_print_table_start();
235         php_info_print_table_header(2, "prpa support", "enabled");
236         php_info_print_table_end();
237
238         /* Remove comments if you have entries in php.ini
239         DISPLAY_INI_ENTRIES();
240         */
241 }
242 /* }}} */
243
244
245 PHP_FUNCTION(rpaparse)
246 {
247         rpadbex_t *dbex;
248         rpastat_t *stat;
249         long rid;
250         long encoding;
251         long ret, i;
252         char *bnf;
253         int bnf_len;
254         char *input;
255         int input_len;
256         zval *error = NULL;
257         zval *zrecords = NULL;
258         rarray_t *records = rpa_records_create();
259
260     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sls|zz", &bnf, &bnf_len, &encoding, &input, &input_len, &zrecords, &error) == FAILURE) {
261                 RETURN_LONG(-1);
262     }
263     dbex = rpa_dbex_create();
264     rpa_dbex_open(dbex);
265     rpa_dbex_load(dbex, bnf, bnf_len);
266     rpa_dbex_close(dbex);
267     rpa_dbex_compile(dbex);
268     stat = rpa_stat_create(dbex, 16000);
269     ret = rpa_stat_parse(stat, rpa_dbex_last(dbex), encoding, input, input, input + input_len, records);
270     if (ret <= 0)
271         goto error;
272     if (zrecords) {
273         rparecord_t *record;
274         array_init(zrecords);
275         for (i = 0; i < rpa_records_length(records); i++) {
276                 zval *zrecord;
277                 record = rpa_records_slot(records, i);
278                 ALLOC_INIT_ZVAL(zrecord);
279                 array_init(zrecord);
280                 add_assoc_stringl(zrecord, "input", (char*)record->input, record->inputsiz, 1);
281                 add_assoc_string(zrecord, "rule", (char*)record->rule, 1);
282                 add_assoc_long(zrecord, "type", record->type);
283                 add_assoc_long(zrecord, "uid", record->ruleuid);
284                 add_next_index_zval(zrecords, zrecord);
285         }
286     }
287
288 error:
289         rpa_records_destroy(records);
290         rpa_stat_destroy(stat);
291         rpa_dbex_destroy(dbex);
292         RETURN_LONG(ret);
293 }
294
295
296 PHP_FUNCTION(rpa_dbex_version)
297 {
298     RETURN_STRING((char*)rpa_dbex_version(), 1);
299 }
300
301
302 static void php_rpa_stat_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
303 {
304     php_rpa_stat *phpstat = (php_rpa_stat*)rsrc->ptr;
305
306     if (phpstat) {
307         rpa_stat_destroy(phpstat->stat);
308         efree(phpstat);
309     }
310 }
311
312
313 static void php_rpa_dbex_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
314 {
315     php_rpa_dbex *pPhpDbex = (php_rpa_dbex*)rsrc->ptr;
316
317     if (pPhpDbex) {
318                 rpa_dbex_destroy(pPhpDbex->hDbex);
319 /*
320                 zval_dtor(pPhpDbex->zcallbacks);
321                 Z_DELREF_P(pPhpDbex->zcallbacks);
322                 Z_DELREF_P(pPhpDbex->zcallbacks);
323                 php_printf("refcnt: %d\n", Z_REFCOUNT_P(pPhpDbex->zcallbacks));
324                 efree(pPhpDbex->zcallbacks);
325 */
326                 efree(pPhpDbex);
327     }
328 }
329
330
331 static void php_rpa_records_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
332 {
333     php_rpa_records *phprecords = (php_rpa_records*)rsrc->ptr;
334
335     if (phprecords) {
336         rpa_records_destroy(phprecords->records);
337         efree(phprecords);
338     }
339 }
340
341
342 PHP_FUNCTION(rpa_dbex_create)
343 {
344     php_rpa_dbex *pPhpDbex;
345
346 /*
347     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &name, &name_len, &age) == FAILURE) {
348                 RETURN_FALSE;
349     }
350 */
351
352     pPhpDbex = emalloc(sizeof(php_rpa_dbex));
353     pPhpDbex->hDbex = rpa_dbex_create();
354
355 /*
356         ALLOC_INIT_ZVAL(pPhpDbex->zcallbacks);
357         Z_ADDREF_P(pPhpDbex->zcallbacks);
358         array_init(pPhpDbex->zcallbacks);
359 */
360     ZEND_REGISTER_RESOURCE(return_value, pPhpDbex, le_rpa_dbex);
361 }
362
363
364 PHP_FUNCTION(rpa_dbex_open)
365 {
366         zval *zres;
367     php_rpa_dbex *pPhpDbex;
368         int ret;
369
370     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
371                 RETURN_LONG(-1);
372     }
373
374     ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
375
376         ret = rpa_dbex_open(pPhpDbex->hDbex);
377         RETURN_LONG(ret);
378 }
379
380
381 PHP_FUNCTION(rpa_dbex_close)
382 {
383         zval *zres;
384     php_rpa_dbex *pPhpDbex;
385
386     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
387                 RETURN_LONG(-1);
388     }
389
390     ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
391
392         rpa_dbex_close(pPhpDbex->hDbex);
393         RETURN_LONG(0);
394 }
395
396
397 PHP_FUNCTION(rpa_dbex_load)
398 {
399         zval *zres;
400     php_rpa_dbex *pPhpDbex;
401         char *patterns;
402         int patterns_len;
403         int ret;
404
405
406     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zres, &patterns, &patterns_len) == FAILURE) {
407                 RETURN_LONG(-1);
408     }
409
410     ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
411
412     ret = rpa_dbex_load_s(pPhpDbex->hDbex, patterns);
413         RETURN_LONG(ret);
414 }
415
416
417 PHP_FUNCTION(rpa_dbex_lookup)
418 {
419         zval *zres;
420     php_rpa_dbex *pPhpDbex;
421         char *name;
422         int name_len;
423         long ret;
424
425     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zres, &name, &name_len) == FAILURE) {
426                 RETURN_LONG(-1);
427     }
428
429     ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
430
431     ret = rpa_dbex_lookup(pPhpDbex->hDbex, name, name_len);
432         RETURN_LONG(ret);
433 }
434
435
436 PHP_FUNCTION(rpa_dbex_first)
437 {
438         zval *zres;
439     php_rpa_dbex *pPhpDbex;
440         long ret;
441
442     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
443                 RETURN_LONG(-1);
444     }
445
446     ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
447
448     ret = rpa_dbex_first(pPhpDbex->hDbex);
449         RETURN_LONG(ret);
450 }
451
452
453 PHP_FUNCTION(rpa_dbex_last)
454 {
455         zval *zres;
456     php_rpa_dbex *pPhpDbex;
457         long ret;
458
459     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
460                 RETURN_LONG(-1);
461     }
462
463     ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
464
465     ret = rpa_dbex_last(pPhpDbex->hDbex);
466         RETURN_LONG(ret);
467 }
468
469
470 PHP_FUNCTION(rpa_dbex_compile)
471 {
472         zval *zres;
473     php_rpa_dbex *pPhpDbex;
474         char *patterns;
475         int patterns_len;
476         int ret;
477
478
479     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
480                 RETURN_LONG(-1);
481     }
482
483     ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
484
485     ret = rpa_dbex_compile(pPhpDbex->hDbex);
486         RETURN_LONG(ret);
487 }
488
489
490 PHP_FUNCTION(rpa_dbex_dumpproductions)
491 {
492         zval *zres;
493     php_rpa_dbex *pPhpDbex;
494         long ret;
495
496     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
497                 RETURN_LONG(-1);
498     }
499
500     ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
501
502     ret = rpa_dbex_dumpproductions(pPhpDbex->hDbex);
503         RETURN_LONG(ret);
504 }
505
506
507 PHP_FUNCTION(rpa_dbex_cfgset)
508 {
509         zval *zres;
510     php_rpa_dbex *pPhpDbex;
511     long cfg, val;
512         long ret;
513
514     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rll", &zres, cfg, val) == FAILURE) {
515                 RETURN_LONG(-1);
516     }
517
518     ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
519
520     ret = rpa_dbex_cfgset(pPhpDbex->hDbex, cfg, val);
521         RETURN_LONG(ret);
522 }
523
524
525 PHP_FUNCTION(rpa_stat_create)
526 {
527         zval *zres;
528     php_rpa_dbex *pPhpDbex;
529     php_rpa_stat *phpstat;
530         int ret;
531         long stackSize = 0L;
532
533
534     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zres, &stackSize) == FAILURE) {
535                 RETURN_LONG(-1);
536     }
537
538     ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
539     phpstat = emalloc(sizeof(php_rpa_stat));
540     phpstat->stat = rpa_stat_create(pPhpDbex->hDbex, stackSize);
541     ZEND_REGISTER_RESOURCE(return_value, phpstat, le_rpa_stat);
542 }
543
544
545 PHP_FUNCTION(rpa_stat_match)
546 {
547         zval *zstat;
548     php_rpa_stat *phpstat;
549         long rid;
550         long encoding;
551         long ret;
552         char *input;
553         int input_len;
554
555     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlls", &zstat, &rid, &encoding, &input, &input_len) == FAILURE) {
556                 RETURN_LONG(-1);
557     }
558     ZEND_FETCH_RESOURCE(phpstat, php_rpa_stat*, &zstat, -1, PHP_RPA_STAT_RES_NAME, le_rpa_stat);
559     ret = rpa_stat_match(phpstat->stat, rid, encoding, input, input, input + input_len);
560         RETURN_LONG(ret);
561 }
562
563
564 PHP_FUNCTION(rpa_stat_scan)
565 {
566         zval *zstat;
567     php_rpa_stat *phpstat;
568         long rid;
569         long encoding;
570         long ret;
571         char *input;
572         int input_len;
573         zval *zwhere;
574         const char *where = NULL;
575
576     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rllsz", &zstat, &rid, &encoding, &input, &input_len, &zwhere) == FAILURE) {
577                 RETURN_LONG(-1);
578     }
579     ZEND_FETCH_RESOURCE(phpstat, php_rpa_stat*, &zstat, -1, PHP_RPA_STAT_RES_NAME, le_rpa_stat);
580     ret = rpa_stat_scan(phpstat->stat, rid, encoding, input, input, input + input_len, &where);
581         if (ret) {
582                 ZVAL_LONG(zwhere, where - input);
583         } else {
584                 ZVAL_NULL(zwhere);
585         }
586
587         RETURN_LONG(ret);
588 }
589
590
591 PHP_FUNCTION(rpa_stat_parse)
592 {
593         zval *zstat;
594     php_rpa_stat *phpstat;
595         long rid;
596         long encoding;
597         long ret, i;
598         char *input;
599         int input_len;
600         zval *zrecords = NULL;
601         rarray_t *records = rpa_records_create();
602
603     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlls|z", &zstat, &rid, &encoding, &input, &input_len, &zrecords) == FAILURE) {
604                 RETURN_LONG(-1);
605     }
606     ZEND_FETCH_RESOURCE(phpstat, php_rpa_stat*, &zstat, -1, PHP_RPA_STAT_RES_NAME, le_rpa_stat);
607     ret = rpa_stat_parse(phpstat->stat, rid, encoding, input, input, input + input_len, records);
608     if (ret <= 0)
609         goto error;
610     if (zrecords) {
611         rparecord_t *record;
612         array_init(zrecords);
613         for (i = 0; i < rpa_records_length(records); i++) {
614                 zval *zrecord;
615                 record = rpa_records_slot(records, i);
616                 ALLOC_INIT_ZVAL(zrecord);
617                 array_init(zrecord);
618                 add_assoc_stringl(zrecord, "input", (char*)record->input, record->inputsiz, 1);
619                 add_assoc_string(zrecord, "rule", (char*)record->rule, 1);
620                 add_assoc_long(zrecord, "type", record->type);
621                 add_assoc_long(zrecord, "uid", record->ruleuid);
622                 add_next_index_zval(zrecords, zrecord);
623         }
624     }
625
626 error:
627         rpa_records_destroy(records);
628         RETURN_LONG(ret);
629 }
630
631
632 PHP_FUNCTION(rpa_records_create)
633 {
634     php_rpa_records *phprecords;
635
636     phprecords = emalloc(sizeof(php_rpa_records));
637     phprecords->records = rpa_records_create();
638
639     ZEND_REGISTER_RESOURCE(return_value, phprecords, le_rpa_dbex);
640 }
641
642
643 #if 0
644 static php_cbinfo *php_cbinfo_create(php_rpa_dbex *pPhpDbex, const char *php_callback, zval *userdata)
645 {
646         php_cbinfo *pCbInfo;
647
648         if ((pCbInfo = emalloc(sizeof(php_cbinfo))) == NULL)
649                 return NULL;
650
651         pCbInfo->pPhpDbex = pPhpDbex;
652         pCbInfo->php_callback = estrdup(php_callback);
653         pCbInfo->userdata = userdata;
654         if (userdata) {
655                 ZVAL_ADDREF(userdata);
656 //              Z_SET_ISREF_P(userdata);
657         }
658         return pCbInfo;
659 }
660
661
662 static void php_cbinfo_destroy(php_cbinfo *pCbInfo)
663 {
664         if (!pCbInfo)
665                 return;
666         if (pCbInfo->php_callback)
667                 efree(pCbInfo->php_callback);
668         if (pCbInfo->userdata) {
669                 if (ZVAL_REFCOUNT(pCbInfo->userdata) == 1) {
670                         zval_ptr_dtor(&pCbInfo->userdata);
671                 } else {
672                         ZVAL_DELREF(pCbInfo->userdata);
673                 }
674         }
675         efree(pCbInfo);
676 }
677
678
679 static void php_do_rpa_dbex_strmatch(INTERNAL_FUNCTION_PARAMETERS, int global) /* {{{ */
680 {
681     /* parameters */
682     char             *subject;          /* String to match against */
683     char             *regex;            /* Regular expression */
684     int               subject_len;
685     int               regex_len;
686         int                               ret = 0;
687
688         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &subject, 
689                                                           &subject_len,
690                                                           &regex,
691                                                           &regex_len) == FAILURE) {
692                 RETURN_LONG(-1);
693     }
694 /*
695         ret = emalloc(subject_len + regex_len + 100);
696         php_sprintf(ret, "Hello from rpalib, subject: %s, regex: %s", subject, regex);
697     RETURN_STRING(ret, 0);
698 */
699         ret = rpa_dbex_strmatch(subject, regex);
700         RETURN_LONG(ret);
701 }
702
703
704 /* {{{ proto int rpa_dbex_strmatch(string subject, string pattern)
705    Perform a regular expression match */
706 PHP_FUNCTION(rpa_dbex_strmatch)
707 {
708     php_do_rpa_dbex_strmatch(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
709 }
710
711
712 PHP_FUNCTION(rpa_dbex_greetme)
713 {
714     zval *zname;
715
716     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zname) == FAILURE) {
717         RETURN_NULL();
718     }
719
720     convert_to_string(zname);
721
722     php_printf("Hello ");
723     PHPWRITE(Z_STRVAL_P(zname), Z_STRLEN_P(zname));
724     php_printf(" ");
725
726     RETURN_TRUE;
727 }
728
729
730
731
732
733
734 PHP_FUNCTION(rpa_dbex_load_string)
735 {
736         zval *zres;
737     php_rpa_dbex *pPhpDbex;
738         char *patterns;
739         int patterns_len;
740         int ret;
741
742
743     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zres, &patterns, &patterns_len) == FAILURE) {
744                 RETURN_LONG(-1);
745     }
746
747     ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
748
749     ret = rpa_dbex_load_string(pPhpDbex->hDbex, patterns);
750         RETURN_LONG(ret);
751 }
752
753
754 PHP_FUNCTION(rpa_dbex_set_encoding)
755 {
756         zval *zres;
757     php_rpa_dbex *pPhpDbex;
758         char *patterns;
759         long encoding;
760         int patterns_len;
761         int ret;
762
763
764     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zres, &encoding) == FAILURE) {
765                 RETURN_LONG(-1);
766     }
767
768     ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
769
770     ret = rpa_dbex_set_encoding(pPhpDbex->hDbex, encoding);
771         RETURN_LONG(ret);
772 }
773
774
775 PHP_FUNCTION(rpa_dbex_match)
776 {
777         zval *zdbex;
778         zval *zpattern;
779         zval *zinput;
780     php_rpa_dbex *pPhpDbex;
781     php_rpa_pattern *pPhpPattern;
782         char *input;
783         int input_len;
784         int ret;
785
786     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrz", &zdbex, &zpattern, &zinput) == FAILURE) {
787                 RETURN_LONG(-1);
788     }
789         input = Z_STRVAL_P(zinput);
790         input_len = Z_STRLEN_P(zinput);
791     ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zdbex, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
792     ZEND_FETCH_RESOURCE(pPhpPattern, php_rpa_pattern*, &zpattern, -1, PHP_RPA_PATTERN_RES_NAME, le_rpa_pattern);
793 #ifdef ZTS
794         pPhpDbex->tsrm_ls = TSRMLS_C;
795 #endif
796         pPhpDbex->zinput = zinput;
797     ret = rpa_dbex_match(pPhpDbex->hDbex, pPhpPattern->hPattern, input, input, input + input_len);
798         RETURN_LONG(ret);
799 }
800
801
802 PHP_FUNCTION(rpa_dbex_parse)
803 {
804         zval *zdbex;
805         zval *zpattern;
806         zval *zinput;
807     php_rpa_dbex *pPhpDbex;
808     php_rpa_pattern *pPhpPattern;
809         char *input;
810         int input_len;
811         int ret;
812
813     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrz", &zdbex, &zpattern, &zinput) == FAILURE) {
814                 RETURN_LONG(-1);
815     }
816         input = Z_STRVAL_P(zinput);
817         input_len = Z_STRLEN_P(zinput);
818     ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zdbex, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
819     ZEND_FETCH_RESOURCE(pPhpPattern, php_rpa_pattern*, &zpattern, -1, PHP_RPA_PATTERN_RES_NAME, le_rpa_pattern);
820 #ifdef ZTS
821         pPhpDbex->tsrm_ls = TSRMLS_C;
822 #endif
823         pPhpDbex->zinput = zinput;
824     ret = rpa_dbex_parse(pPhpDbex->hDbex, pPhpPattern->hPattern, input, input, input + input_len);
825         RETURN_LONG(ret);
826 }
827
828
829 PHP_FUNCTION(rpa_dbex_scan)
830 {
831         zval *zdbex;
832         zval *zpattern;
833         zval *zinput;
834         zval *zwhere;
835     php_rpa_dbex *pPhpDbex;
836     php_rpa_pattern *pPhpPattern;
837         char *input;
838         const char *where = NULL;
839         int input_len;
840         int ret;
841
842     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrzz", &zdbex, &zpattern, &zinput, &zwhere) == FAILURE) {
843                 RETURN_LONG(-1);
844     }
845         input = Z_STRVAL_P(zinput);
846         input_len = Z_STRLEN_P(zinput);
847     ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zdbex, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
848     ZEND_FETCH_RESOURCE(pPhpPattern, php_rpa_pattern*, &zpattern, -1, PHP_RPA_PATTERN_RES_NAME, le_rpa_pattern);
849 #ifdef ZTS
850         pPhpDbex->tsrm_ls = TSRMLS_C;
851 #endif
852         pPhpDbex->zinput = zinput;
853     ret = rpa_dbex_scan(pPhpDbex->hDbex, pPhpPattern->hPattern, input, input, input + input_len, &where);
854         if (ret) {
855                 ZVAL_LONG(zwhere, where - input);
856         } else {
857                 ZVAL_NULL(zwhere);
858         }
859
860         RETURN_LONG(ret);
861 }
862
863
864 PHP_FUNCTION(rpa_dbex_get_pattern)
865 {
866         zval *zres;
867         php_rpa_dbex *pPhpDbex;
868         php_rpa_pattern *pPhpPattern;
869         char *name;
870         int name_len;
871         rpa_pattern_handle hPattern;
872
873         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zres, &name, &name_len) == FAILURE) {
874                 RETURN_FALSE;
875         }
876         ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
877         hPattern = rpa_dbex_get_pattern(pPhpDbex->hDbex, name);
878         if (!hPattern)
879                 RETURN_FALSE;
880         pPhpPattern = emalloc(sizeof(php_rpa_pattern));
881         pPhpPattern->hPattern = hPattern;
882         ZEND_REGISTER_RESOURCE(return_value, pPhpPattern, le_rpa_pattern);
883 }
884
885
886 PHP_FUNCTION(rpa_dbex_default_pattern)
887 {
888         zval *zres;
889         php_rpa_dbex *pPhpDbex;
890         php_rpa_pattern *pPhpPattern;
891         rpa_pattern_handle hPattern;
892
893         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
894                 RETURN_FALSE;
895         }
896         ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
897         hPattern = rpa_dbex_default_pattern(pPhpDbex->hDbex);
898         if (!hPattern)
899                 RETURN_FALSE;
900         pPhpPattern = emalloc(sizeof(php_rpa_pattern));
901         pPhpPattern->hPattern = hPattern;
902         ZEND_REGISTER_RESOURCE(return_value, pPhpPattern, le_rpa_pattern);
903 }
904
905
906 PHP_FUNCTION(rpa_dbex_first_pattern)
907 {
908         zval *zres;
909         php_rpa_dbex *pPhpDbex;
910         php_rpa_pattern *pPhpPattern;
911         rpa_pattern_handle hPattern;
912
913         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
914                 RETURN_FALSE;
915         }
916         ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
917         hPattern = rpa_dbex_first_pattern(pPhpDbex->hDbex);
918         if (!hPattern)
919                 RETURN_FALSE;
920         pPhpPattern = emalloc(sizeof(php_rpa_pattern));
921         pPhpPattern->hPattern = hPattern;
922         ZEND_REGISTER_RESOURCE(return_value, pPhpPattern, le_rpa_pattern);
923 }
924
925
926 PHP_FUNCTION(rpa_dbex_last_pattern)
927 {
928         zval *zres;
929         php_rpa_dbex *pPhpDbex;
930         php_rpa_pattern *pPhpPattern;
931         rpa_pattern_handle hPattern;
932
933         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
934                 RETURN_FALSE;
935         }
936         ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
937         hPattern = rpa_dbex_last_pattern(pPhpDbex->hDbex);
938         if (!hPattern)
939                 RETURN_FALSE;
940         pPhpPattern = emalloc(sizeof(php_rpa_pattern));
941         pPhpPattern->hPattern = hPattern;
942         ZEND_REGISTER_RESOURCE(return_value, pPhpPattern, le_rpa_pattern);
943 }
944
945
946 PHP_FUNCTION(rpa_dbex_next_pattern)
947 {
948         zval *zresFirst, *zresSecond;
949         php_rpa_dbex *pPhpDbex;
950         php_rpa_pattern *pPhpPatternCur;
951         php_rpa_pattern *pPhpPattern;
952         rpa_pattern_handle hPattern;
953
954         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &zresFirst, &zresSecond) == FAILURE) {
955                 RETURN_FALSE;
956         }
957         ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zresFirst, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
958     ZEND_FETCH_RESOURCE(pPhpPatternCur, php_rpa_pattern*, &zresSecond, -1, PHP_RPA_PATTERN_RES_NAME, le_rpa_pattern);
959                 
960         hPattern = rpa_dbex_next_pattern(pPhpDbex ? pPhpDbex->hDbex : NULL, pPhpPatternCur ? pPhpPatternCur->hPattern : NULL);
961         if (!hPattern)
962                 RETURN_FALSE;
963         pPhpPattern = emalloc(sizeof(php_rpa_pattern));
964         pPhpPattern->hPattern = hPattern;
965         ZEND_REGISTER_RESOURCE(return_value, pPhpPattern, le_rpa_pattern);
966 }
967
968
969 PHP_FUNCTION(rpa_dbex_prev_pattern)
970 {
971         zval *zresFirst, *zresSecond;
972         php_rpa_dbex *pPhpDbex;
973         php_rpa_pattern *pPhpPatternCur;
974         php_rpa_pattern *pPhpPattern;
975         rpa_pattern_handle hPattern;
976
977         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &zresFirst, &zresSecond) == FAILURE) {
978                 RETURN_FALSE;
979         }
980         ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zresFirst, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
981     ZEND_FETCH_RESOURCE(pPhpPatternCur, php_rpa_pattern*, &zresSecond, -1, PHP_RPA_PATTERN_RES_NAME, le_rpa_pattern);
982                 
983         hPattern = rpa_dbex_prev_pattern(pPhpDbex ? pPhpDbex->hDbex : NULL, pPhpPatternCur ? pPhpPatternCur->hPattern : NULL);
984         if (!hPattern)
985                 RETURN_FALSE;
986         pPhpPattern = emalloc(sizeof(php_rpa_pattern));
987         pPhpPattern->hPattern = hPattern;
988         ZEND_REGISTER_RESOURCE(return_value, pPhpPattern, le_rpa_pattern);
989 }
990
991
992 PHP_FUNCTION(rpa_dbex_pattern_name)
993 {
994         zval *zresFirst, *zresSecond;
995         php_rpa_dbex *pPhpDbex;
996         php_rpa_pattern *pPhpPattern;
997         const char *name;
998         char *ret;
999
1000         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &zresFirst, &zresSecond) == FAILURE) {
1001                 RETURN_FALSE;
1002         }
1003         ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zresFirst, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
1004     ZEND_FETCH_RESOURCE(pPhpPattern, php_rpa_pattern*, &zresSecond, -1, PHP_RPA_PATTERN_RES_NAME, le_rpa_pattern);
1005                 
1006         name = rpa_dbex_pattern_name(pPhpDbex ? pPhpDbex->hDbex : NULL, pPhpPattern ? pPhpPattern->hPattern : NULL);
1007         if (!name)
1008                 RETURN_FALSE;
1009         ret = estrdup(name);
1010         RETURN_STRING(ret, 0);
1011 }
1012
1013
1014 PHP_FUNCTION(rpa_dbex_pattern_regex)
1015 {
1016         zval *zresFirst, *zresSecond;
1017         php_rpa_dbex *pPhpDbex;
1018         php_rpa_pattern *pPhpPattern;
1019         long int seq = 0;
1020         const char *regex;
1021         char *ret;
1022
1023         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr|l", &zresFirst, &zresSecond, &seq) == FAILURE) {
1024                 RETURN_FALSE;
1025         }
1026         ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zresFirst, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
1027     ZEND_FETCH_RESOURCE(pPhpPattern, php_rpa_pattern*, &zresSecond, -1, PHP_RPA_PATTERN_RES_NAME, le_rpa_pattern);
1028                 
1029         regex = rpa_dbex_pattern_regex(pPhpDbex ? pPhpDbex->hDbex : NULL, pPhpPattern ? pPhpPattern->hPattern : NULL, seq);
1030         if (!regex)
1031                 RETURN_FALSE;
1032         ret = estrdup(regex);
1033         RETURN_STRING(ret, 0);
1034 }
1035
1036
1037 static int php_rpa_callback_proxy(const char *name, void *userdata, const char *input, unsigned int size, unsigned int reason, const char *start, const char *end)
1038 {
1039         php_cbinfo *pCbInfo = (php_cbinfo*)userdata;
1040         zval *retval_ptr = NULL;  /* Function return value */
1041     zval **args[7];           /* Argument to pass to function */
1042         zval *zcallback;
1043         zval *zname;
1044         zval *zoffset;
1045         zval *zsize;
1046         zval *zreason;
1047         zval *zuserdata;
1048         zval *zempty;
1049         int ret = size;
1050 #ifdef ZTS
1051         TSRMLS_D = pCbInfo->pPhpDbex->tsrm_ls;
1052 #endif
1053
1054         MAKE_STD_ZVAL(zcallback);
1055         MAKE_STD_ZVAL(zname);
1056         MAKE_STD_ZVAL(zoffset);
1057         MAKE_STD_ZVAL(zsize);
1058         MAKE_STD_ZVAL(zreason);
1059         MAKE_STD_ZVAL(zuserdata);
1060         MAKE_STD_ZVAL(zempty);
1061
1062         ZVAL_STRING(zcallback, pCbInfo->php_callback, 1);
1063         ZVAL_LONG(zsize, size);
1064         ZVAL_LONG(zreason, reason);
1065         ZVAL_LONG(zempty, 0);
1066         ZVAL_LONG(zoffset, input - start);
1067         ZVAL_STRING(zname, name, 1);
1068
1069         args[0] = &zname;
1070         if (pCbInfo->userdata) {
1071                 args[1] = &pCbInfo->userdata;
1072         } else {
1073                 args[1] = &zempty;
1074         }
1075
1076
1077         args[2] = &zoffset;
1078         args[3] = &zsize;
1079         args[4] = &zreason;
1080         args[5] = &pCbInfo->pPhpDbex->zinput;
1081
1082
1083         if (call_user_function_ex(EG(function_table), NULL, zcallback, &retval_ptr, 6, args, 0, NULL TSRMLS_CC) == SUCCESS && retval_ptr) {
1084                 convert_to_long(retval_ptr);
1085                 ret = (int) Z_LVAL_P(retval_ptr);
1086                 zval_ptr_dtor(&retval_ptr);
1087         } else {
1088                 if (!EG(exception)) {
1089                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call function: %s()", Z_STRVAL_P(zcallback));
1090                 }
1091         }
1092
1093 /*
1094         zval_ptr_dtor(&zcallback);
1095         zval_ptr_dtor(&zname);
1096         zval_ptr_dtor(&zsize);
1097         zval_ptr_dtor(&zreason);
1098         zval_ptr_dtor(&zuserdata);
1099         zval_ptr_dtor(&zoffset);
1100         zval_ptr_dtor(&zempty);
1101 */
1102
1103         return ret;
1104 }
1105
1106
1107 PHP_FUNCTION(rpa_dbex_add_callback)
1108 {
1109         zval *zresDbex, *zresCallback, *zresUserData = NULL;
1110         php_rpa_dbex *pPhpDbex;
1111         php_rpa_pattern *pPhpPattern;
1112         char *name;
1113         long reason;
1114         int name_len = 0;
1115         char *callback;
1116         int callback_len = 0;
1117         unsigned long ret = 0;
1118         php_cbinfo *pCbInfo;
1119
1120         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsls|z", &zresDbex, &name, &name_len, &reason, 
1121                                                           &callback, &callback_len, &zresUserData) == FAILURE) {
1122                 RETURN_LONG(-1);
1123         }
1124         ZEND_FETCH_RESOURCE(pPhpDbex, php_rpa_dbex*, &zresDbex, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
1125
1126         pCbInfo = php_cbinfo_create(pPhpDbex, callback, zresUserData);
1127         ret = rpa_dbex_add_callback(pPhpDbex ? pPhpDbex->hDbex : NULL, name, reason, php_rpa_callback_proxy, pCbInfo);
1128         RETURN_LONG(ret);
1129 }
1130
1131 #endif