RPA Toolkit
added ini file parsing test.
[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         if (zrecords)
630                 ZVAL_NULL(zrecords);
631         rpa_records_destroy(records);
632         RETURN_LONG(ret);
633     }
634     if (zrecords) {
635         rpa_records2array(input, records, zrecords);
636     }
637         rpa_records_destroy(records);
638         RETURN_LONG(ret);
639 }
640
641
642 PHP_FUNCTION(rpaparse)
643 {
644         char buffer[1000];
645         rpadbex_t *dbex = NULL;
646         rpastat_t *stat = NULL;
647         long rid;
648         long encoding;
649         long ret, i;
650         char *bnf;
651         int bnf_len;
652         char *input;
653         int input_len;
654         zval *zerror = NULL;
655         zval *zrecords = NULL;
656         rarray_t *records = rpa_records_create();
657
658     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sls|zz", &bnf, &bnf_len, &encoding, &input, &input_len, &zrecords, &zerror) == FAILURE) {
659                 RETURN_LONG(-1);
660     }
661     memset(buffer, 0, sizeof(buffer));
662     dbex = rpa_dbex_create();
663     if (rpa_dbex_open(dbex) < 0)
664         goto dbexerror;
665     if (rpa_dbex_load(dbex, bnf, bnf_len) < 0)
666         goto dbexerror;
667     rpa_dbex_close(dbex);
668     if (rpa_dbex_compile(dbex) < 0)
669         goto dbexerror;
670     stat = rpa_stat_create(dbex, 16000);
671     ret = rpa_stat_parse(stat, rpa_dbex_last(dbex), encoding, input, input, input + input_len, records);
672     if (ret < 0)
673         goto staterror;
674     if (ret > 0 && zrecords) {
675         rpa_records2array(input, records, zrecords);
676     }
677
678         if (zerror) {
679                 ZVAL_NULL(zerror);
680         }
681         rpa_records_destroy(records);
682         rpa_stat_destroy(stat);
683         rpa_dbex_destroy(dbex);
684         RETURN_LONG(ret);
685
686 dbexerror:
687         if (zerror) {
688                 rpa_dbex_geterrorstr(dbex, buffer, sizeof(buffer) - 1);
689                 ZVAL_STRING(zerror, buffer, 1);
690         }
691 //      if (zrecords)
692 //              ZVAL_NULL(zrecords);
693         rpa_records_destroy(records);
694         rpa_stat_destroy(stat);
695         rpa_dbex_destroy(dbex);
696         RETURN_LONG(-1);
697
698 staterror:
699         if (zerror) {
700                 rpa_stat_geterrorstr(stat, buffer, sizeof(buffer) - 1);
701                 ZVAL_STRING(zerror, buffer, 1);
702         }
703 //      if (zrecords)
704 //              ZVAL_NULL(zrecords);
705         rpa_records_destroy(records);
706         rpa_stat_destroy(stat);
707         rpa_dbex_destroy(dbex);
708         RETURN_LONG(-1);
709 }
710
711
712 PHP_FUNCTION(rpascan)
713 {
714         char buffer[1000];
715         rpadbex_t *dbex = NULL;
716         rpastat_t *stat = NULL;
717         long rid;
718         long encoding;
719         long ret, i;
720         char *bnf;
721         int bnf_len;
722         char *input;
723         const rchar *where = NULL;
724         int input_len;
725         zval *zerror = NULL;
726         zval *zwhere = NULL;
727
728     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sls|zz", &bnf, &bnf_len, &encoding, &input, &input_len, &zwhere, &zerror) == FAILURE) {
729                 RETURN_LONG(-1);
730     }
731     memset(buffer, 0, sizeof(buffer));
732     dbex = rpa_dbex_create();
733     if (rpa_dbex_open(dbex) < 0)
734         goto dbexerror;
735     if (rpa_dbex_load(dbex, bnf, bnf_len) < 0)
736         goto dbexerror;
737     rpa_dbex_close(dbex);
738     if (rpa_dbex_compile(dbex) < 0)
739         goto dbexerror;
740     stat = rpa_stat_create(dbex, 16000);
741     ret = rpa_stat_scan(stat, rpa_dbex_last(dbex), encoding, input, input, input + input_len, &where);
742     if (ret < 0)
743         goto staterror;
744     if (zwhere) {
745                 if (ret > 0 && where) {
746                         ZVAL_LONG(zwhere, where - input);
747                 } else {
748                         ZVAL_NULL(zwhere);
749                 }
750     }
751         if (zerror) {
752                 ZVAL_NULL(zerror);
753         }
754         rpa_stat_destroy(stat);
755         rpa_dbex_destroy(dbex);
756         RETURN_LONG(ret);
757
758 dbexerror:
759         if (zerror) {
760                 rpa_dbex_geterrorstr(dbex, buffer, sizeof(buffer) - 1);
761                 ZVAL_STRING(zerror, buffer, 1);
762         }
763         rpa_stat_destroy(stat);
764         rpa_dbex_destroy(dbex);
765         RETURN_LONG(-1);
766
767 staterror:
768         if (zerror) {
769                 rpa_stat_geterrorstr(stat, buffer, sizeof(buffer) - 1);
770                 ZVAL_STRING(zerror, buffer, 1);
771         }
772         rpa_stat_destroy(stat);
773         rpa_dbex_destroy(dbex);
774         RETURN_LONG(-1);
775
776 }
777
778
779 PHP_FUNCTION(rpamatch)
780 {
781         char buffer[1000];
782         rpadbex_t *dbex = NULL;
783         rpastat_t *stat = NULL;
784         long rid;
785         long encoding;
786         long ret, i;
787         char *bnf;
788         int bnf_len;
789         char *input;
790         int input_len;
791         zval *zerror = NULL;
792
793     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sls|z", &bnf, &bnf_len, &encoding, &input, &input_len, &zerror) == FAILURE) {
794                 RETURN_LONG(-1);
795     }
796     memset(buffer, 0, sizeof(buffer));
797     dbex = rpa_dbex_create();
798     if (rpa_dbex_open(dbex) < 0)
799         goto dbexerror;
800     if (rpa_dbex_load(dbex, bnf, bnf_len) < 0)
801         goto dbexerror;
802     rpa_dbex_close(dbex);
803     if (rpa_dbex_compile(dbex) < 0)
804         goto dbexerror;
805     stat = rpa_stat_create(dbex, 16000);
806     ret = rpa_stat_match(stat, rpa_dbex_last(dbex), encoding, input, input, input + input_len);
807     if (ret < 0)
808         goto staterror;
809         if (zerror) {
810                 ZVAL_NULL(zerror);
811         }
812         rpa_stat_destroy(stat);
813         rpa_dbex_destroy(dbex);
814         RETURN_LONG(ret);
815
816 dbexerror:
817         if (zerror) {
818                 rpa_dbex_geterrorstr(dbex, buffer, sizeof(buffer) - 1);
819                 ZVAL_STRING(zerror, buffer, 1);
820         }
821         rpa_stat_destroy(stat);
822         rpa_dbex_destroy(dbex);
823         RETURN_LONG(-1);
824
825 staterror:
826         if (zerror) {
827                 rpa_stat_geterrorstr(stat, buffer, sizeof(buffer) - 1);
828                 ZVAL_STRING(zerror, buffer, 1);
829         }
830         rpa_stat_destroy(stat);
831         rpa_dbex_destroy(dbex);
832         RETURN_LONG(-1);
833
834 }
835