RPA Toolkit
Implemented the PHP extension for RPA.
[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* dbex;
38 #ifdef ZTS
39         TSRMLS_D;       
40 #endif
41 } php_rpa_dbex;
42
43 #define PHP_RPA_DBEX_RES_NAME "php rpa dbex"
44
45
46 typedef struct _php_rpa_stat {
47         rpastat_t* stat;
48 #ifdef ZTS
49         TSRMLS_D;
50 #endif
51 } php_rpa_stat;
52
53 #define PHP_RPA_STAT_RES_NAME "php rpa stat"
54
55 static int le_rpa_dbex;
56 static int le_rpa_stat;
57 static void php_rpa_dbex_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC);
58 static void php_rpa_stat_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC);
59
60
61 /* If you declare any globals in php_prpa.h uncomment this:
62 ZEND_DECLARE_MODULE_GLOBALS(prpa)
63 */
64
65 /* True global resources - no need for thread safety here */
66 static int le_prpa;
67
68 /* {{{ prpa_functions[]
69  *
70  * Every user visible function must have an entry in prpa_functions[].
71  */
72 zend_function_entry prpa_functions[] = {
73     PHP_FE(rpaparse, NULL)
74     PHP_FE(rpascan, NULL)
75     PHP_FE(rpamatch, NULL)
76     PHP_FE(rpa_dbex_version, NULL)
77     PHP_FE(rpa_dbex_create, NULL)
78     PHP_FE(rpa_dbex_open, NULL)
79     PHP_FE(rpa_dbex_close, NULL)
80     PHP_FE(rpa_dbex_load, NULL)
81     PHP_FE(rpa_dbex_compile, NULL)
82     PHP_FE(rpa_dbex_lookup, NULL)
83     PHP_FE(rpa_dbex_first, NULL)
84     PHP_FE(rpa_dbex_last, NULL)
85     PHP_FE(rpa_dbex_cfgset, NULL)
86     PHP_FE(rpa_dbex_dumpproductions, NULL)
87     PHP_FE(rpa_dbex_error, NULL)
88     PHP_FE(rpa_stat_create, NULL)
89     PHP_FE(rpa_stat_match, NULL)
90     PHP_FE(rpa_stat_scan, NULL)
91     PHP_FE(rpa_stat_parse, NULL)
92     PHP_FE(rpa_stat_error, NULL)
93         {NULL, NULL, NULL}      /* Must be the last line in prpa_functions[] */
94 };
95 /* }}} */
96
97 /* {{{ prpa_module_entry
98  */
99 zend_module_entry prpa_module_entry = {
100 #if ZEND_MODULE_API_NO >= 20010901
101         STANDARD_MODULE_HEADER,
102 #endif
103         "prpa",
104         prpa_functions,
105         PHP_MINIT(prpa),
106         PHP_MSHUTDOWN(prpa),
107         PHP_RINIT(prpa),                /* Replace with NULL if there's nothing to do at request start */
108         PHP_RSHUTDOWN(prpa),    /* Replace with NULL if there's nothing to do at request end */
109         PHP_MINFO(prpa),
110 #if ZEND_MODULE_API_NO >= 20010901
111         "0.1", /* Replace with version number for your extension */
112 #endif
113         STANDARD_MODULE_PROPERTIES
114 };
115 /* }}} */
116
117 #ifdef COMPILE_DL_PRPA
118 ZEND_GET_MODULE(prpa)
119 #endif
120
121 /* {{{ PHP_INI
122  */
123 /* Remove comments and fill if you need to have entries in php.ini
124 PHP_INI_BEGIN()
125     STD_PHP_INI_ENTRY("prpa.global_value",      "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_prpa_globals, prpa_globals)
126     STD_PHP_INI_ENTRY("prpa.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_prpa_globals, prpa_globals)
127 PHP_INI_END()
128 */
129 /* }}} */
130
131 /* {{{ php_prpa_init_globals
132  */
133 /* Uncomment this function if you have INI entries
134 static void php_prpa_init_globals(zend_prpa_globals *prpa_globals)
135 {
136         prpa_globals->global_value = 0;
137         prpa_globals->global_string = NULL;
138 }
139 */
140 /* }}} */
141
142 /* {{{ PHP_MINIT_FUNCTION
143  */
144 PHP_MINIT_FUNCTION(prpa)
145 {
146         /* If you have INI entries, uncomment these lines 
147         REGISTER_INI_ENTRIES();
148         */
149     le_rpa_dbex = zend_register_list_destructors_ex(php_rpa_dbex_dtor, NULL, PHP_RPA_DBEX_RES_NAME, module_number);
150     le_rpa_stat = zend_register_list_destructors_ex(php_rpa_stat_dtor, NULL, PHP_RPA_STAT_RES_NAME, module_number);
151     REGISTER_LONG_CONSTANT("RPA_ENCODING_BYTE", RPA_ENCODING_BYTE, CONST_CS | CONST_PERSISTENT);
152     REGISTER_LONG_CONSTANT("RPA_ENCODING_UTF8", RPA_ENCODING_UTF8, CONST_CS | CONST_PERSISTENT);
153     REGISTER_LONG_CONSTANT("RPA_ENCODING_ICASE_UTF8", RPA_ENCODING_ICASE_UTF8, CONST_CS | CONST_PERSISTENT);
154     REGISTER_LONG_CONSTANT("RPA_ENCODING_UTF16LE", RPA_ENCODING_UTF16LE, CONST_CS | CONST_PERSISTENT);
155     REGISTER_LONG_CONSTANT("RPA_ENCODING_ICASE_UTF16LE", RPA_ENCODING_ICASE_UTF16LE, CONST_CS | CONST_PERSISTENT);
156     REGISTER_LONG_CONSTANT("RPA_RECORD_START", RPA_RECORD_START, CONST_CS | CONST_PERSISTENT);
157     REGISTER_LONG_CONSTANT("RPA_RECORD_END", RPA_RECORD_END, CONST_CS | CONST_PERSISTENT);
158     REGISTER_LONG_CONSTANT("RPA_DBEXCFG_DEBUG", RPA_DBEXCFG_DEBUG, CONST_CS | CONST_PERSISTENT);
159     REGISTER_LONG_CONSTANT("RPA_DBEXCFG_OPTIMIZATIONS", RPA_DBEXCFG_OPTIMIZATIONS, CONST_CS | CONST_PERSISTENT);
160         return SUCCESS;
161 }
162 /* }}} */
163
164 /* {{{ PHP_MSHUTDOWN_FUNCTION
165  */
166 PHP_MSHUTDOWN_FUNCTION(prpa)
167 {
168         /* uncomment this line if you have INI entries
169         UNREGISTER_INI_ENTRIES();
170         */
171         return SUCCESS;
172 }
173 /* }}} */
174
175 /* Remove if there's nothing to do at request start */
176 /* {{{ PHP_RINIT_FUNCTION
177  */
178 PHP_RINIT_FUNCTION(prpa)
179 {
180         return SUCCESS;
181 }
182 /* }}} */
183
184 /* Remove if there's nothing to do at request end */
185 /* {{{ PHP_RSHUTDOWN_FUNCTION
186  */
187 PHP_RSHUTDOWN_FUNCTION(prpa)
188 {
189         return SUCCESS;
190 }
191 /* }}} */
192
193 /* {{{ PHP_MINFO_FUNCTION
194  */
195 PHP_MINFO_FUNCTION(prpa)
196 {
197         php_info_print_table_start();
198         php_info_print_table_header(2, "prpa support", "enabled");
199         php_info_print_table_end();
200
201         /* Remove comments if you have entries in php.ini
202         DISPLAY_INI_ENTRIES();
203         */
204 }
205 /* }}} */
206
207
208 PHP_FUNCTION(rpa_dbex_version)
209 {
210     RETURN_STRING((char*)rpa_dbex_version(), 1);
211 }
212
213
214 static void php_rpa_stat_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
215 {
216     php_rpa_stat *phpstat = (php_rpa_stat*)rsrc->ptr;
217
218     if (phpstat) {
219         rpa_stat_destroy(phpstat->stat);
220         efree(phpstat);
221     }
222 }
223
224
225 static void php_rpa_dbex_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
226 {
227     php_rpa_dbex *phpdbex = (php_rpa_dbex*)rsrc->ptr;
228
229     if (phpdbex) {
230                 rpa_dbex_destroy(phpdbex->dbex);
231                 efree(phpdbex);
232     }
233 }
234
235
236 PHP_FUNCTION(rpa_dbex_create)
237 {
238     php_rpa_dbex *phpdbex;
239
240     phpdbex = emalloc(sizeof(php_rpa_dbex));
241     phpdbex->dbex = rpa_dbex_create();
242     ZEND_REGISTER_RESOURCE(return_value, phpdbex, le_rpa_dbex);
243 }
244
245
246 PHP_FUNCTION(rpa_dbex_open)
247 {
248         zval *zres;
249     php_rpa_dbex *phpdbex;
250         int ret;
251
252     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
253                 RETURN_LONG(-1);
254     }
255
256     ZEND_FETCH_RESOURCE(phpdbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
257
258         ret = rpa_dbex_open(phpdbex->dbex);
259         RETURN_LONG(ret);
260 }
261
262
263 PHP_FUNCTION(rpa_dbex_close)
264 {
265         zval *zres;
266     php_rpa_dbex *phpdbex;
267
268     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
269                 RETURN_LONG(-1);
270     }
271
272     ZEND_FETCH_RESOURCE(phpdbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
273
274         rpa_dbex_close(phpdbex->dbex);
275         RETURN_LONG(0);
276 }
277
278
279 PHP_FUNCTION(rpa_dbex_load)
280 {
281         zval *zres;
282     php_rpa_dbex *phpdbex;
283         char *patterns;
284         int patterns_len;
285         int ret;
286
287
288     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zres, &patterns, &patterns_len) == FAILURE) {
289                 RETURN_LONG(-1);
290     }
291
292     ZEND_FETCH_RESOURCE(phpdbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
293
294     ret = rpa_dbex_load_s(phpdbex->dbex, patterns);
295         RETURN_LONG(ret);
296 }
297
298
299 PHP_FUNCTION(rpa_dbex_lookup)
300 {
301         zval *zres;
302     php_rpa_dbex *phpdbex;
303         char *name;
304         int name_len;
305         long ret;
306
307     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zres, &name, &name_len) == FAILURE) {
308                 RETURN_LONG(-1);
309     }
310
311     ZEND_FETCH_RESOURCE(phpdbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
312
313     ret = rpa_dbex_lookup(phpdbex->dbex, name, name_len);
314         RETURN_LONG(ret);
315 }
316
317
318 PHP_FUNCTION(rpa_dbex_first)
319 {
320         zval *zres;
321     php_rpa_dbex *phpdbex;
322         long ret;
323
324     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
325                 RETURN_LONG(-1);
326     }
327
328     ZEND_FETCH_RESOURCE(phpdbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
329
330     ret = rpa_dbex_first(phpdbex->dbex);
331         RETURN_LONG(ret);
332 }
333
334
335 PHP_FUNCTION(rpa_dbex_last)
336 {
337         zval *zres;
338     php_rpa_dbex *phpdbex;
339         long ret;
340
341     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
342                 RETURN_LONG(-1);
343     }
344     ZEND_FETCH_RESOURCE(phpdbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
345     ret = rpa_dbex_last(phpdbex->dbex);
346         RETURN_LONG(ret);
347 }
348
349
350 PHP_FUNCTION(rpa_dbex_compile)
351 {
352         zval *zres;
353     php_rpa_dbex *phpdbex;
354         char *patterns;
355         int patterns_len;
356         int ret;
357
358     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
359                 RETURN_LONG(-1);
360     }
361     ZEND_FETCH_RESOURCE(phpdbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
362     ret = rpa_dbex_compile(phpdbex->dbex);
363         RETURN_LONG(ret);
364 }
365
366
367 PHP_FUNCTION(rpa_dbex_dumpproductions)
368 {
369         zval *zres;
370     php_rpa_dbex *phpdbex;
371         long ret;
372
373     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
374                 RETURN_LONG(-1);
375     }
376     ZEND_FETCH_RESOURCE(phpdbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
377     ret = rpa_dbex_dumpproductions(phpdbex->dbex);
378         RETURN_LONG(ret);
379 }
380
381
382 PHP_FUNCTION(rpa_dbex_cfgset)
383 {
384         zval *zres;
385     php_rpa_dbex *phpdbex;
386     long cfg, val;
387         long ret;
388
389     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rll", &zres, cfg, val) == FAILURE) {
390                 RETURN_LONG(-1);
391     }
392     ZEND_FETCH_RESOURCE(phpdbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
393     ret = rpa_dbex_cfgset(phpdbex->dbex, cfg, val);
394         RETURN_LONG(ret);
395 }
396
397
398 static rchar *dbexmsg[] = {
399         "OK",
400         "Out of memory",
401         "Invalid input.",
402         "Expression database is not open.",
403         "Expression database is not closed.",
404         "Expression name is not found.",
405         "Syntax error.",
406         "Unresolved expression name.",
407         "Invalid parameter.",
408         "Failed to compile rule.",
409         "Database is not compiled.",
410         "Unknown",
411         "Unknown",
412         "Unknown",
413         "Unknown",
414         "Unknown",
415         "Unknown",
416         "Unknown",
417 };
418
419
420 static rchar *statmsg[] = {
421         "OK",
422         "Execution error.",
423         "Execution aborted by user.",
424         "Aborted on expression.",
425         "Unknown",
426         "Unknown",
427         "Unknown",
428         "Unknown",
429         "Unknown",
430         "Unknown",
431         "Unknown",
432 };
433
434
435 static void rpa_dbex_geterrorstr(rpadbex_t *dbex, char *buffer, size_t size)
436 {
437         long n = 0;
438         char *ptr = buffer;
439         rpa_errinfo_t errorinfo;
440
441         memset(&errorinfo, 0, sizeof(errorinfo));
442     rpa_dbex_lasterrorinfo(dbex, &errorinfo);
443     if (!errorinfo.code)
444         return;
445     if (errorinfo.mask & RPA_ERRINFO_CODE) {
446         if (errorinfo.code >= 1000 && errorinfo.code < 1010)
447                 n += snprintf(ptr + n, size - n, "%s Code: %ld. ", dbexmsg[errorinfo.code - 1000], errorinfo.code);
448     }
449     if (errorinfo.mask & RPA_ERRINFO_LINE) {
450         n += snprintf(ptr + n, size - n, "Line: %ld. ", errorinfo.line);
451     }
452     if (errorinfo.mask & RPA_ERRINFO_OFFSET) {
453         n += snprintf(ptr + n, size - n, "Offset: %ld. ", errorinfo.offset);
454     }
455     if (errorinfo.mask & RPA_ERRINFO_RULEID) {
456         n += snprintf(ptr + n, size - n, "RuleId: %ld. ", errorinfo.ruleid);
457     }
458     if (errorinfo.mask & RPA_ERRINFO_NAME) {
459         n += snprintf(ptr + n, size - n, "Name: %s. ", errorinfo.name);
460     }
461
462 }
463
464
465 PHP_FUNCTION(rpa_dbex_error)
466 {
467         zval *zres;
468         char buffer[1000];
469     php_rpa_dbex *phpdbex;
470
471         memset(buffer, 0, sizeof(buffer));
472     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
473                 RETURN_LONG(-1);
474     }
475     ZEND_FETCH_RESOURCE(phpdbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
476     rpa_dbex_geterrorstr(phpdbex->dbex, buffer, sizeof(buffer) - 1);
477         RETURN_STRING(buffer, 1);
478 }
479
480
481 static void rpa_stat_geterrorstr(rpastat_t *stat, char *buffer, size_t size)
482 {
483         long n = 0;
484         char *ptr = buffer;
485         rpa_errinfo_t errorinfo;
486
487         memset(&errorinfo, 0, sizeof(errorinfo));
488     rpa_stat_lasterrorinfo(stat, &errorinfo);
489     if (!errorinfo.code)
490         return;
491     if (errorinfo.mask & RPA_ERRINFO_CODE) {
492         if (errorinfo.code >= 2000 && errorinfo.code < 2010)
493                 n += snprintf(ptr + n, size - n, "%s Code: %ld. ", statmsg[errorinfo.code - 2000], errorinfo.code);
494     }
495     if (errorinfo.mask & RPA_ERRINFO_LINE) {
496         n += snprintf(ptr + n, size - n, "Line: %ld. ", errorinfo.line);
497     }
498     if (errorinfo.mask & RPA_ERRINFO_OFFSET) {
499         n += snprintf(ptr + n, size - n, "Offset: %ld. ", errorinfo.offset);
500     }
501     if (errorinfo.mask & RPA_ERRINFO_RULEID) {
502         n += snprintf(ptr + n, size - n, "RuleId: %ld. ", errorinfo.ruleid);
503     }
504     if (errorinfo.mask & RPA_ERRINFO_NAME) {
505         n += snprintf(ptr + n, size - n, "Name: %s. ", errorinfo.name);
506     }
507
508 }
509
510
511 static void rpa_records2array(const rchar *input, rarray_t *records, zval *zrecords)
512 {
513         rlong i;
514
515         rparecord_t *record;
516         array_init(zrecords);
517         for (i = 0; i < rpa_records_length(records); i++) {
518                 zval *zrecord;
519                 record = rpa_records_slot(records, i);
520                 ALLOC_INIT_ZVAL(zrecord);
521                 array_init(zrecord);
522                 add_assoc_stringl(zrecord, "input", (char*)record->input, record->inputsiz, 1);
523                 add_assoc_string(zrecord, "rule", (char*)record->rule, 1);
524                 add_assoc_long(zrecord, "type", record->type);
525                 add_assoc_long(zrecord, "uid", record->ruleuid);
526                 add_assoc_long(zrecord, "offset", record->input - input);
527                 add_assoc_long(zrecord, "size", record->inputsiz);
528                 add_next_index_zval(zrecords, zrecord);
529         }
530 }
531
532 PHP_FUNCTION(rpa_stat_error)
533 {
534         zval *zres;
535         char buffer[1000];
536     php_rpa_stat *phpstat;
537
538         memset(buffer, 0, sizeof(buffer));
539     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) {
540                 RETURN_LONG(-1);
541     }
542     ZEND_FETCH_RESOURCE(phpstat, php_rpa_stat*, &zres, -1, PHP_RPA_STAT_RES_NAME, le_rpa_stat);
543     rpa_stat_geterrorstr(phpstat->stat, buffer, sizeof(buffer) - 1);
544         RETURN_STRING(buffer, 1);
545 }
546
547
548 PHP_FUNCTION(rpa_stat_create)
549 {
550         zval *zres;
551     php_rpa_dbex *phpdbex;
552     php_rpa_stat *phpstat;
553         int ret;
554         long stackSize = 0L;
555
556     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zres, &stackSize) == FAILURE) {
557                 RETURN_LONG(-1);
558     }
559     ZEND_FETCH_RESOURCE(phpdbex, php_rpa_dbex*, &zres, -1, PHP_RPA_DBEX_RES_NAME, le_rpa_dbex);
560     phpstat = emalloc(sizeof(php_rpa_stat));
561     phpstat->stat = rpa_stat_create(phpdbex->dbex, stackSize);
562     ZEND_REGISTER_RESOURCE(return_value, phpstat, le_rpa_stat);
563 }
564
565
566 PHP_FUNCTION(rpa_stat_match)
567 {
568         zval *zstat;
569     php_rpa_stat *phpstat;
570         long rid;
571         long encoding;
572         long ret;
573         char *input;
574         int input_len;
575
576     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlls", &zstat, &rid, &encoding, &input, &input_len) == 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_match(phpstat->stat, rid, encoding, input, input, input + input_len);
581         RETURN_LONG(ret);
582 }
583
584
585 PHP_FUNCTION(rpa_stat_scan)
586 {
587         zval *zstat;
588     php_rpa_stat *phpstat;
589         long rid;
590         long encoding;
591         long ret;
592         char *input;
593         int input_len;
594         zval *zwhere;
595         const char *where = NULL;
596
597     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rllsz", &zstat, &rid, &encoding, &input, &input_len, &zwhere) == FAILURE) {
598                 RETURN_LONG(-1);
599     }
600     ZEND_FETCH_RESOURCE(phpstat, php_rpa_stat*, &zstat, -1, PHP_RPA_STAT_RES_NAME, le_rpa_stat);
601     ret = rpa_stat_scan(phpstat->stat, rid, encoding, input, input, input + input_len, &where);
602         if (ret > 0) {
603                 ZVAL_LONG(zwhere, where - input);
604         } else {
605                 ZVAL_NULL(zwhere);
606         }
607         RETURN_LONG(ret);
608 }
609
610
611 PHP_FUNCTION(rpa_stat_parse)
612 {
613         zval *zstat;
614     php_rpa_stat *phpstat;
615         long rid;
616         long encoding;
617         long ret, i;
618         char *input;
619         int input_len;
620         zval *zrecords = NULL;
621         rarray_t *records = rpa_records_create();
622
623     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlls|z", &zstat, &rid, &encoding, &input, &input_len, &zrecords) == FAILURE) {
624                 RETURN_LONG(-1);
625     }
626     ZEND_FETCH_RESOURCE(phpstat, php_rpa_stat*, &zstat, -1, PHP_RPA_STAT_RES_NAME, le_rpa_stat);
627     ret = rpa_stat_parse(phpstat->stat, rid, encoding, input, input, input + input_len, records);
628     if (ret <= 0)
629         goto error;
630     if (zrecords) {
631         rpa_records2array(input, records, zrecords);
632     }
633
634 error:
635         rpa_records_destroy(records);
636         RETURN_LONG(ret);
637 }
638
639
640 PHP_FUNCTION(rpaparse)
641 {
642         char buffer[1000];
643         rpadbex_t *dbex = NULL;
644         rpastat_t *stat = NULL;
645         long rid;
646         long encoding;
647         long ret, i;
648         char *bnf;
649         int bnf_len;
650         char *input;
651         int input_len;
652         zval *zerror = NULL;
653         zval *zrecords = NULL;
654         rarray_t *records = rpa_records_create();
655
656     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sls|zz", &bnf, &bnf_len, &encoding, &input, &input_len, &zrecords, &zerror) == FAILURE) {
657                 RETURN_LONG(-1);
658     }
659     memset(buffer, 0, sizeof(buffer));
660     dbex = rpa_dbex_create();
661     if (rpa_dbex_open(dbex) < 0)
662         goto dbexerror;
663     if (rpa_dbex_load(dbex, bnf, bnf_len) < 0)
664         goto dbexerror;
665     rpa_dbex_close(dbex);
666     if (rpa_dbex_compile(dbex) < 0)
667         goto dbexerror;
668     stat = rpa_stat_create(dbex, 16000);
669     ret = rpa_stat_parse(stat, rpa_dbex_last(dbex), encoding, input, input, input + input_len, records);
670     if (ret < 0)
671         goto staterror;
672     if (ret > 0 && zrecords) {
673         rpa_records2array(input, records, zrecords);
674     }
675
676         if (zerror) {
677                 ZVAL_NULL(zerror);
678         }
679         rpa_records_destroy(records);
680         rpa_stat_destroy(stat);
681         rpa_dbex_destroy(dbex);
682         RETURN_LONG(ret);
683
684 dbexerror:
685         if (zerror) {
686                 rpa_dbex_geterrorstr(dbex, buffer, sizeof(buffer) - 1);
687                 ZVAL_STRING(zerror, buffer, 1);
688         }
689         rpa_records_destroy(records);
690         rpa_stat_destroy(stat);
691         rpa_dbex_destroy(dbex);
692         RETURN_LONG(-1);
693
694 staterror:
695         if (zerror) {
696                 rpa_stat_geterrorstr(stat, buffer, sizeof(buffer) - 1);
697                 ZVAL_STRING(zerror, buffer, 1);
698         }
699         rpa_records_destroy(records);
700         rpa_stat_destroy(stat);
701         rpa_dbex_destroy(dbex);
702         RETURN_LONG(-1);
703 }
704
705
706 PHP_FUNCTION(rpascan)
707 {
708         char buffer[1000];
709         rpadbex_t *dbex = NULL;
710         rpastat_t *stat = NULL;
711         long rid;
712         long encoding;
713         long ret, i;
714         char *bnf;
715         int bnf_len;
716         char *input;
717         const rchar *where = NULL;
718         int input_len;
719         zval *zerror = NULL;
720         zval *zwhere = NULL;
721
722     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sls|zz", &bnf, &bnf_len, &encoding, &input, &input_len, &zwhere, &zerror) == FAILURE) {
723                 RETURN_LONG(-1);
724     }
725     memset(buffer, 0, sizeof(buffer));
726     dbex = rpa_dbex_create();
727     if (rpa_dbex_open(dbex) < 0)
728         goto dbexerror;
729     if (rpa_dbex_load(dbex, bnf, bnf_len) < 0)
730         goto dbexerror;
731     rpa_dbex_close(dbex);
732     if (rpa_dbex_compile(dbex) < 0)
733         goto dbexerror;
734     stat = rpa_stat_create(dbex, 16000);
735     ret = rpa_stat_scan(stat, rpa_dbex_last(dbex), encoding, input, input, input + input_len, &where);
736     if (ret < 0)
737         goto staterror;
738     if (zwhere) {
739                 if (ret > 0 && where) {
740                         ZVAL_LONG(zwhere, where - input);
741                 } else {
742                         ZVAL_NULL(zwhere);
743                 }
744     }
745         if (zerror) {
746                 ZVAL_NULL(zerror);
747         }
748         rpa_stat_destroy(stat);
749         rpa_dbex_destroy(dbex);
750         RETURN_LONG(ret);
751
752 dbexerror:
753         if (zerror) {
754                 rpa_dbex_geterrorstr(dbex, buffer, sizeof(buffer) - 1);
755                 ZVAL_STRING(zerror, buffer, 1);
756         }
757         rpa_stat_destroy(stat);
758         rpa_dbex_destroy(dbex);
759         RETURN_LONG(-1);
760
761 staterror:
762         if (zerror) {
763                 rpa_stat_geterrorstr(stat, buffer, sizeof(buffer) - 1);
764                 ZVAL_STRING(zerror, buffer, 1);
765         }
766         rpa_stat_destroy(stat);
767         rpa_dbex_destroy(dbex);
768         RETURN_LONG(-1);
769
770 }
771
772
773 PHP_FUNCTION(rpamatch)
774 {
775         char buffer[1000];
776         rpadbex_t *dbex = NULL;
777         rpastat_t *stat = NULL;
778         long rid;
779         long encoding;
780         long ret, i;
781         char *bnf;
782         int bnf_len;
783         char *input;
784         int input_len;
785         zval *zerror = NULL;
786
787     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sls|z", &bnf, &bnf_len, &encoding, &input, &input_len, &zerror) == FAILURE) {
788                 RETURN_LONG(-1);
789     }
790     memset(buffer, 0, sizeof(buffer));
791     dbex = rpa_dbex_create();
792     if (rpa_dbex_open(dbex) < 0)
793         goto dbexerror;
794     if (rpa_dbex_load(dbex, bnf, bnf_len) < 0)
795         goto dbexerror;
796     rpa_dbex_close(dbex);
797     if (rpa_dbex_compile(dbex) < 0)
798         goto dbexerror;
799     stat = rpa_stat_create(dbex, 16000);
800     ret = rpa_stat_match(stat, rpa_dbex_last(dbex), encoding, input, input, input + input_len);
801     if (ret < 0)
802         goto staterror;
803         if (zerror) {
804                 ZVAL_NULL(zerror);
805         }
806         rpa_stat_destroy(stat);
807         rpa_dbex_destroy(dbex);
808         RETURN_LONG(ret);
809
810 dbexerror:
811         if (zerror) {
812                 rpa_dbex_geterrorstr(dbex, buffer, sizeof(buffer) - 1);
813                 ZVAL_STRING(zerror, buffer, 1);
814         }
815         rpa_stat_destroy(stat);
816         rpa_dbex_destroy(dbex);
817         RETURN_LONG(-1);
818
819 staterror:
820         if (zerror) {
821                 rpa_stat_geterrorstr(stat, buffer, sizeof(buffer) - 1);
822                 ZVAL_STRING(zerror, buffer, 1);
823         }
824         rpa_stat_destroy(stat);
825         rpa_dbex_destroy(dbex);
826         RETURN_LONG(-1);
827
828 }
829