RPA Toolkit
deleted commented out code
[rpatk.git] / rpa / rpastat.c
1 /*
2  *  Regular Pattern Analyzer (RPA)
3  *  Copyright (c) 2009-2010 Martin Stoilov
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  *  Martin Stoilov <martin@rpasearch.com>
19  */
20
21 #include "rlib/rmem.h"
22 #include "rlib/rarray.h"
23 #include "rpa/rpastatpriv.h"
24 #include "rvm/rvmcodegen.h"
25 #include "rvm/rvmcpu.h"
26 #include "rlib/rutf.h"
27 #include "rlib/rcharconv.h"
28
29
30 rpastat_t *rpa_stat_create(rpadbex_t *dbex, unsigned long stacksize)
31 {
32         rpastat_t *stat = (rpastat_t *) r_zmalloc(sizeof(*stat));
33         if (stacksize == 0)
34                 stacksize = RPA_DEFAULT_STACKSIZE;
35         stat->cpu = rpavm_cpu_create(stacksize);
36         stat->cache = rpa_cache_create();
37         if (!stat->cpu) {
38                 r_free(stat);
39                 return NULL;
40         }
41         stat->dbex = dbex;
42         stat->cpu->userdata1 = stat;
43         return stat;
44 }
45
46
47 void rpa_stat_destroy(rpastat_t *stat)
48 {
49         if (stat) {
50                 if (stat->instackbuffer)
51                         r_free(stat->instackbuffer);
52                 rpavm_cpu_destroy(stat->cpu);
53                 rpa_cache_destroy(stat->cache);
54                 r_free(stat);
55         }
56 }
57
58
59 void rpa_stat_cachedisable(rpastat_t *stat, unsigned int disable)
60 {
61         rpa_cache_disable(stat->cache, disable);
62 }
63
64
65 int rpa_stat_init(rpastat_t *stat, unsigned int encoding, const char *input, const char *start, const char *end, rarray_t *records)
66 {
67         unsigned long size;
68
69         if (!stat) {
70                 return -1;
71         }
72         if (start > end) {
73                 return -1;
74         }
75         if (input < start || input > end) {
76                 return -1;
77         }
78         r_memset(&stat->err, 0, sizeof(stat->err));
79         size = end - start;
80         stat->encoding = encoding;
81         stat->start = start;
82         stat->end = end;
83         stat->input = input;
84         stat->cache->hit = 0;
85         stat->records = records;
86         if (stat->instacksize == 0 || stat->instacksize < size) {
87                 stat->instackbuffer = r_realloc(stat->instackbuffer, (size + 2) * sizeof(rpainput_t));
88                 stat->instacksize = size;
89                 stat->instack = &stat->instackbuffer[1];
90                 r_memset(stat->instackbuffer, 0, sizeof(rpainput_t) * 2);
91
92         }
93         stat->ip.input = input;
94         stat->ip.serial = 0;
95         RVM_CPUREG_SETL(stat->cpu, R_REC, 0);
96         RVM_CPUREG_SETU(stat->cpu, SP, 0);
97         RVM_CPUREG_SETU(stat->cpu, FP, 0);
98         RVM_CPUREG_SETU(stat->cpu, R_LOO, 0);
99         RVM_CPUREG_SETU(stat->cpu, R_TOP, -1);
100         if (stat->records) {
101                 RVM_CPUREG_SETL(stat->cpu, R_REC, (long)(r_array_length(stat->records) - 1));
102         }
103         return 0;
104 }
105
106
107 void rpa_stat_cacheinvalidate(rpastat_t *stat)
108 {
109         rpa_cache_invalidate(stat->cache);
110 }
111
112
113 long rpa_stat_exec(rpastat_t *stat, rvm_asmins_t *prog, rword off, unsigned int encoding, const char *input, const char *start, const char *end, rarray_t *records)
114 {
115         long ret;
116
117         if (!stat) {
118                 return -1;
119         }
120         rpa_stat_cacheinvalidate(stat);
121         rpa_stat_init(stat, encoding, input, start, end, records);
122
123         if (stat->debug) {
124                 ret = rvm_cpu_exec_debug(stat->cpu, prog, off);
125         } else {
126                 ret = rvm_cpu_exec(stat->cpu, prog, off);
127         }
128         if (ret < 0) {
129                 if (!stat->cpu->error) {
130                         if (stat->cpu->error) {
131                                 RPA_STAT_SETERROR_CODE(stat, stat->cpu->error);
132                         } else {
133                                 /*
134                                  * We should never get to here. Error have to be more
135                                  * specific and set at the places they are detected.
136                                  */
137                                 RPA_STAT_SETERROR_CODE(stat, RPA_E_EXECUTION);
138                         }
139                 }
140                 return -1;
141         }
142         ret = (long)RVM_CPUREG_GETL(stat->cpu, R0);
143         if (ret < 0) {
144                 return 0;
145         }
146         return ret;
147 }
148
149
150 static long rpa_stat_exec_rid(rpastat_t *stat, rparule_t rid, unsigned int encoding, const char *input, const char *start, const char *end, rarray_t *records)
151 {
152         long topsiz = 0;
153         rpainput_t *ptp;
154         long offset;
155         rvm_asmins_t *exec;
156
157
158         exec = rpa_dbex_executable(stat->dbex);
159         if (!exec) {
160                 RPA_STAT_SETERROR_CODE(stat, RPA_E_EXECUTION);
161                 return -1;
162         }
163         offset = rpa_dbex_executableoffset(stat->dbex, rid);
164         if (offset < 0) {
165                 RPA_STAT_SETERROR_CODE(stat, RPA_E_EXECUTION);
166                 return -1;
167         }
168         if ((topsiz = rpa_stat_exec(stat, exec, offset, encoding, input, start, end, records)) < 0) {
169                 return -1;
170         }
171         if (topsiz <= 0)
172                 return 0;
173         ptp = &stat->instack[topsiz];
174         return (ptp->input - input);
175 }
176
177
178 long rpa_stat_scan(rpastat_t *stat, rparule_t rid, unsigned int encoding, const char *input, const char *start, const char *end, const char **where)
179 {
180         long ret;
181         long topsiz = 0;
182         rpainput_t *ptp;
183         long offset;
184         rvm_asmins_t *exec;
185
186         exec = rpa_dbex_executable(stat->dbex);
187         if (!exec) {
188                 RPA_STAT_SETERROR_CODE(stat, RPA_E_EXECUTION);
189                 return -1;
190         }
191         offset = rpa_dbex_executableoffset(stat->dbex, rid);
192         if (offset < 0) {
193                 RPA_STAT_SETERROR_CODE(stat, RPA_E_EXECUTION);
194                 return -1;
195         }
196
197         while (input < end) {
198                 topsiz = rpa_stat_exec(stat, exec, offset, encoding, input, start, end, NULL);
199                 if (topsiz < 0) {
200                         if (rpa_stat_lasterror(stat) != RPA_E_RULEABORT) {
201                                 return -1;
202                         }
203                 }
204                 if (topsiz > 0) {
205                         ptp = &stat->instack[topsiz];
206                         ret = (ptp->input - input);
207                         *where = input;
208                         return ret;
209                 }
210                 if (topsiz == 0) {
211                         ptp = &stat->instack[0];
212                         input += stat->ip.input - ptp->input;
213                 } else {
214                         input += 1;
215                 }
216         }
217         return 0;
218 }
219
220
221 long rpa_stat_match(rpastat_t *stat, rparule_t rid, unsigned int encoding, const char *input, const char *start, const char *end)
222 {
223         return rpa_stat_exec_rid(stat, rid, encoding, input, start, end, NULL);
224 }
225
226
227 long rpa_stat_parse(rpastat_t *stat, rparule_t rid, unsigned int encoding, const char *input, const char *start, const char *end, rarray_t *records)
228 {
229         return rpa_stat_exec_rid(stat, rid, encoding, input, start, end, records);
230 }
231
232
233 int rpa_stat_abort(rpastat_t *stat)
234 {
235         if (!stat) {
236                 return -1;
237         }
238         RPA_STAT_SETERROR_CODE(stat, RPA_E_USERABORT);
239         rvm_cpu_abort(stat->cpu);
240         return 0;
241 }
242
243
244 rboolean rpa_stat_matchbitmap(rpastat_t *stat, rssize_t top, rpabitmap_t bitmap)
245 {
246         int ret = FALSE;
247         rpainput_t *in = &stat->instack[top];
248
249         if (in->eof)
250                 return 0;
251         if (stat->encoding & RPA_ENCODING_ICASE) {
252                 ret = (RPA_BITMAP_GETBIT(&bitmap, in->wc % RPA_BITMAP_BITS) || RPA_BITMAP_GETBIT(&bitmap, in->iwc % RPA_BITMAP_BITS)) ? TRUE : FALSE;
253         } else {
254                 ret = (RPA_BITMAP_GETBIT(&bitmap, in->wc % RPA_BITMAP_BITS)) ? TRUE : FALSE;
255         }
256         return ret;
257 }
258
259
260 int rpa_stat_matchchr(rpastat_t *stat, rssize_t top, unsigned long wc)
261 {
262         int ret = 0;
263         rpainput_t *in = &stat->instack[top];
264
265         if (in->eof)
266                 return 0;
267         if (stat->encoding & RPA_ENCODING_ICASE) {
268                 ret = (in->wc == wc || in->iwc == wc) ? 1 : 0;
269         } else {
270                 ret = (in->wc == wc) ? 1 : 0;
271         }
272         return ret;
273 }
274
275
276 unsigned long rpa_special_char(unsigned long special)
277 {
278         unsigned long wc;
279
280         switch (special) {
281                 case '.':
282                         wc = '.';
283                         break;
284                 case 't':
285                         wc = '\t';
286                         break;
287                 case 'r':
288                         wc = '\r';
289                         break;
290                 case 'n':
291                         wc = '\n';
292                         break;
293                 default:
294                         wc = special;
295                         break;
296         };
297
298         return wc;
299 }
300
301
302 int rpa_stat_matchspchr(rpastat_t *stat, rssize_t top, unsigned long wc)
303 {
304         int ret = 0;
305         rpainput_t *in = &stat->instack[top];
306
307         if (in->eof)
308                 return 0;
309         wc = rpa_special_char(wc);
310         if (wc == '.')
311                 return 1;
312         ret = (in->wc == wc) ? 1 : 0;
313         return ret;
314 }
315
316
317 int rpa_stat_matchrng(rpastat_t *stat, rssize_t top, unsigned long wc1, unsigned long wc2)
318 {
319         int ret = 0;
320         rpainput_t *in = &stat->instack[top];
321
322         if (in->eof)
323                 return 0;
324         if (stat->encoding & RPA_ENCODING_ICASE) {
325                 ret = ((in->wc >= wc1 && in->wc <= wc2) || (in->iwc >= wc1 && in->iwc <= wc2)) ? 1 : 0;
326         } else {
327                 ret = ((in->wc >= wc1 && in->wc <= wc2)) ? 1 : 0;
328         }
329         return ret;
330 }
331
332
333 static int rpa_stat_utf8_getchar(ruint32 *pwc, rpastat_t *stat, const char *input)
334 {
335         return r_utf8_mbtowc(pwc, (const unsigned char*)input, (const unsigned char*)stat->end);
336 }
337
338
339 static int rpa_stat_byte_getchar(ruint32 *pwc, rpastat_t *stat, const char *input)
340 {
341         if (input >= stat->end) {
342                 *pwc = (unsigned int)0;
343                 return 0;
344         }
345         *pwc = *((const unsigned char*)input);
346         return 1;
347 }
348
349
350 static int rpa_stat_utf16_getchar(ruint32 *pwc, rpastat_t *stat, const char *input)
351 {
352         return r_utf16_mbtowc(pwc, (const unsigned char*)input, (const unsigned char*)stat->end);
353 }
354
355
356 long rpa_stat_shift(rpastat_t *stat, rssize_t top)
357 {
358         rpainput_t * ptp = &stat->instack[top];
359
360         if (ptp->eof)
361                 return -1;
362         ptp++;
363         top++;
364         if (top >= (long)stat->ip.serial) {
365                 int inc = 0;
366                 ptp->input = stat->ip.input;
367                 if (ptp->input < stat->end) {
368                         switch (stat->encoding & RPA_ENCODING_MASK) {
369                         default:
370                         case RPA_ENCODING_UTF8:
371                                 inc = rpa_stat_utf8_getchar(&ptp->wc, stat, (const char*)stat->ip.input);
372                                 break;
373                         case RPA_ENCODING_UTF16LE:
374                                 inc = rpa_stat_utf16_getchar(&ptp->wc, stat, (const char*)stat->ip.input);
375                                 break;
376                         case RPA_ENCODING_BYTE:
377                                 inc = rpa_stat_byte_getchar(&ptp->wc, stat, (const char*)stat->ip.input);
378                                 break;
379                         };
380                         if (stat->encoding & RPA_ENCODING_ICASE)
381                                 ptp->iwc = r_charicase(ptp->wc);
382                         stat->ip.input += inc;
383                         stat->ip.serial += 1;
384                         ptp->eof = 0;
385                 } else {
386                         ptp->wc = (ruint32)-1;
387                         ptp->eof = 1;
388                 }
389         }
390
391         return top;
392 }
393
394
395 long rpa_stat_lasterror(rpastat_t *stat)
396 {
397         if (!stat)
398                 return -1;
399         return stat->err.code;
400 }
401
402
403 long rpa_stat_lasterrorinfo(rpastat_t *stat, rpa_errinfo_t *errinfo)
404 {
405         if (!stat || !errinfo)
406                 return -1;
407         r_memcpy(errinfo, &stat->err, sizeof(rpa_errinfo_t));
408         return 0;
409 }