RPA Toolkit
01bc77069be0f127ea9c0f78fa125ba5724eacf1
[rpatk.git] / rpa / rpastat.c
1 #include "rmem.h"
2 #include "rarray.h"
3 #include "rpastatpriv.h"
4 #include "rvmcodegen.h"
5 #include "rvmcpu.h"
6 #include "rutf.h"
7 #include "rcharconv.h"
8
9
10 rpastat_t *rpa_stat_create(rpadbex_t *dbex, rulong stacksize)
11 {
12         rpastat_t *stat = (rpastat_t *) r_zmalloc(sizeof(*stat));
13         if (stacksize == 0)
14                 stacksize = RPA_DEFAULT_STACKSIZE;
15         stat->cpu = rpavm_cpu_create(stacksize);
16         stat->cache = rpa_cache_create();
17         if (!stat->cpu) {
18                 r_free(stat);
19                 return NULL;
20         }
21         stat->dbex = dbex;
22         stat->cpu->userdata1 = stat;
23         return stat;
24 }
25
26
27 void rpa_stat_destroy(rpastat_t *stat)
28 {
29         if (stat) {
30                 if (stat->instack)
31                         r_free(stat->instackbuffer);
32                 rpavm_cpu_destroy(stat->cpu);
33                 rpa_cache_destroy(stat->cache);
34                 r_free(stat);
35         }
36 }
37
38
39 void rpa_stat_cachedisable(rpastat_t *stat, ruint disable)
40 {
41         rpa_cache_disable(stat->cache, disable);
42 }
43
44
45 rint rpa_stat_init(rpastat_t *stat, const rchar *input, const rchar *start, const rchar *end, rarray_t *records)
46 {
47         rulong size;
48
49         if (!stat) {
50                 return -1;
51         }
52         if (start > end) {
53                 return -1;
54         }
55         if (input < start || input > end) {
56                 return -1;
57         }
58         r_memset(&stat->err, 0, sizeof(stat->err));
59         size = end - start;
60         stat->start = start;
61         stat->end = end;
62         stat->input = input;
63         stat->cache->hit = 0;
64         stat->records = records;
65         if (stat->instacksize < size) {
66                 stat->instackbuffer = r_realloc(stat->instackbuffer, (size + 2) * sizeof(rpainput_t));
67                 stat->instacksize = size + 1;
68                 stat->instack = &stat->instackbuffer[1];
69                 r_memset(stat->instackbuffer, 0, sizeof(rpainput_t) * 2);
70         }
71         stat->ip.input = input;
72         stat->ip.serial = 0;
73         RVM_CPUREG_SETL(stat->cpu, R_REC, 0);
74         RVM_CPUREG_SETU(stat->cpu, SP, 0);
75         RVM_CPUREG_SETU(stat->cpu, FP, 0);
76         RVM_CPUREG_SETU(stat->cpu, R_LOO, 0);
77         RVM_CPUREG_SETU(stat->cpu, R_TOP, -1);
78         if (stat->records) {
79                 RVM_CPUREG_SETL(stat->cpu, R_REC, (rlong)(r_array_length(stat->records) - 1));
80         }
81         return 0;
82 }
83
84
85 void rpa_stat_cacheinvalidate(rpastat_t *stat)
86 {
87         rpa_cache_invalidate(stat->cache);
88 }
89
90
91 rint rpa_stat_setencoding(rpastat_t *stat, ruint encoding)
92 {
93         if (!stat) {
94                 return -1;
95         }
96
97         stat->encoding = encoding;
98         return 0;
99 }
100
101
102 rlong rpa_stat_exec(rpastat_t *stat, rvm_asmins_t *prog, rword off, const rchar *input, const rchar *start, const rchar *end, rarray_t *records)
103 {
104         rlong ret;
105
106         if (!stat) {
107                 return -1;
108         }
109         rpa_stat_cacheinvalidate(stat);
110         rpa_stat_init(stat, input, start, end, records);
111         if (stat->debug) {
112                 ret = rvm_cpu_exec_debug(stat->cpu, prog, off);
113         } else {
114                 ret = rvm_cpu_exec(stat->cpu, prog, off);
115         }
116         if (ret < 0) {
117                 if (!stat->cpu->error) {
118                         if (stat->cpu->error) {
119                                 RPA_STAT_SETERROR_CODE(stat, stat->cpu->error);
120                         } else {
121                                 /*
122                                  * We should never get to here. Error have to be more
123                                  * specific and set at the places they are detected.
124                                  */
125                                 RPA_STAT_SETERROR_CODE(stat, RPA_E_EXECUTION);
126                         }
127                 }
128                 return -1;
129         }
130         ret = (rlong)RVM_CPUREG_GETL(stat->cpu, R0);
131         if (ret < 0) {
132                 return 0;
133         }
134         return ret;
135 }
136
137
138 static rlong rpa_stat_exec_rid(rpastat_t *stat, rparule_t rid, const rchar *input, const rchar *start, const rchar *end, rarray_t *records)
139 {
140         rlong topsiz = 0;
141         rpainput_t *ptp;
142
143         if ((topsiz = rpa_stat_exec(stat, rpa_dbex_executable(stat->dbex), rpa_dbex_executableoffset(stat->dbex, rid),  input, start, end, records)) < 0) {
144                 return -1;
145         }
146         if (topsiz <= 0)
147                 return 0;
148         ptp = &stat->instack[topsiz];
149         return (ptp->input - input);
150 }
151
152
153 rlong rpa_stat_scan(rpastat_t *stat, rparule_t rid, const rchar *input, const rchar *start, const rchar *end, const rchar **where)
154 {
155         rlong ret;
156
157         while (input < end) {
158                 ret = rpa_stat_exec_rid(stat, rid, input, start, end, NULL);
159                 if (ret < 0)
160                         return -1;
161                 if (ret > 0) {
162                         *where = input;
163                         return ret;
164                 }
165                 input += 1;
166         }
167         return ret;
168 }
169
170
171 rlong rpa_stat_match(rpastat_t *stat, rparule_t rid, const rchar *input, const rchar *start, const rchar *end)
172 {
173         return rpa_stat_exec_rid(stat, rid, input, start, end, NULL);
174 }
175
176
177 rlong rpa_stat_parse(rpastat_t *stat, rparule_t rid, const rchar *input, const rchar *start, const rchar *end, rarray_t *records)
178 {
179         return rpa_stat_exec_rid(stat, rid, input, start, end, records);
180 }
181
182
183 rint rpa_stat_abort(rpastat_t *stat)
184 {
185         if (!stat) {
186                 return -1;
187         }
188         RPA_STAT_SETERROR_CODE(stat, RPA_E_USERABORT);
189         rvm_cpu_abort(stat->cpu);
190         return 0;
191 }
192
193
194 rint rpa_stat_matchchr(rpastat_t *stat, rssize_t top, rulong wc)
195 {
196         rint ret = 0;
197         rpainput_t *in = &stat->instack[top];
198
199         if (in->eof)
200                 return 0;
201         if (stat->encoding & RPA_ENCODING_ICASE) {
202                 ret = (in->wc == wc || in->iwc == wc) ? 1 : 0;
203         } else {
204                 ret = (in->wc == wc) ? 1 : 0;
205         }
206         return ret;
207 }
208
209
210 rint rpa_stat_matchspchr(rpastat_t *stat, rssize_t top, rulong wc)
211 {
212         rint ret = 0;
213         rpainput_t *in = &stat->instack[top];
214
215         if (in->eof)
216                 return 0;
217
218         switch (wc) {
219                 case '.':
220                         return 1;
221                         break;
222                 case 't':
223                         wc = '\t';
224                         break;
225                 case 'r':
226                         wc = '\r';
227                         break;
228                 case 'n':
229                         wc = '\n';
230                         break;
231                 default:
232                         break;
233         };
234
235         ret = (in->wc == wc) ? 1 : 0;
236         return ret;
237 }
238
239
240 rint rpa_stat_matchrng(rpastat_t *stat, rssize_t top, rulong wc1, rulong wc2)
241 {
242         rint ret = 0;
243         rpainput_t *in = &stat->instack[top];
244
245         if (in->eof)
246                 return 0;
247         if (stat->encoding & RPA_ENCODING_ICASE) {
248                 ret = ((in->wc >= wc1 && in->wc <= wc2) || (in->iwc >= wc1 && in->iwc <= wc2)) ? 1 : 0;
249         } else {
250                 ret = ((in->wc >= wc1 && in->wc <= wc2)) ? 1 : 0;
251         }
252         return ret;
253 }
254
255
256 static rint rpa_stat_utf8_getchar(ruint32 *pwc, rpastat_t *stat, const rchar *input)
257 {
258         return r_utf8_mbtowc(pwc, (const ruchar*)input, (const ruchar*)stat->end);
259 }
260
261
262 static rint rpa_stat_byte_getchar(ruint32 *pwc, rpastat_t *stat, const rchar *input)
263 {
264         if (input >= stat->end) {
265                 *pwc = (unsigned int)0;
266                 return 0;
267         }
268         *pwc = *((const ruchar*)input);
269         return 1;
270 }
271
272
273 static int rpa_stat_utf16_getchar(ruint32 *pwc, rpastat_t *stat, const rchar *input)
274 {
275         return r_utf16_mbtowc(pwc, (const ruchar*)input, (const ruchar*)stat->end);
276 }
277
278
279 rlong rpa_stat_shift(rpastat_t *stat, rssize_t top)
280 {
281         rpainput_t * ptp = &stat->instack[top];
282
283         if (ptp->eof)
284                 return -1;
285         ptp++;
286         top++;
287         if (top >= (rlong)stat->ip.serial) {
288                 rint inc = 0;
289                 ptp->input = stat->ip.input;
290                 if (ptp->input < stat->end) {
291                         switch (stat->encoding & RPA_ENCODING_MASK) {
292                         default:
293                         case RPA_ENCODING_UTF8:
294                                 inc = rpa_stat_utf8_getchar(&ptp->wc, stat, (const rchar*)stat->ip.input);
295                                 break;
296                         case RPA_ENCODING_UTF16LE:
297                                 inc = rpa_stat_utf16_getchar(&ptp->wc, stat, (const rchar*)stat->ip.input);
298                                 break;
299                         case RPA_ENCODING_BYTE:
300                                 inc = rpa_stat_byte_getchar(&ptp->wc, stat, (const rchar*)stat->ip.input);
301                                 break;
302                         };
303                         if (stat->encoding & RPA_ENCODING_ICASE)
304                                 ptp->iwc = r_charicase(ptp->wc);
305                         stat->ip.input += inc;
306                         stat->ip.serial += 1;
307                         ptp->eof = 0;
308                 } else {
309                         ptp->wc = (ruint32)-1;
310                         ptp->eof = 1;
311                 }
312         }
313
314         return top;
315 }
316
317
318 rlong rpa_stat_lasterror(rpastat_t *stat)
319 {
320         if (!stat)
321                 return -1;
322         return stat->err.code;
323 }
324
325
326 rlong rpa_stat_lasterrorinfo(rpastat_t *stat, rpa_errinfo_t *errinfo)
327 {
328         if (!stat || !errinfo)
329                 return -1;
330         r_memcpy(errinfo, &stat->err, sizeof(rpa_errinfo_t));
331         return 0;
332 }