RPA Toolkit
Refined the rpastat_t public interface. Added more API documentation.
[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, ruint encoding, 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->encoding = encoding;
61         stat->start = start;
62         stat->end = end;
63         stat->input = input;
64         stat->cache->hit = 0;
65         stat->records = records;
66         if (stat->instacksize < size) {
67                 stat->instackbuffer = r_realloc(stat->instackbuffer, (size + 2) * sizeof(rpainput_t));
68                 stat->instacksize = size + 1;
69                 stat->instack = &stat->instackbuffer[1];
70                 r_memset(stat->instackbuffer, 0, sizeof(rpainput_t) * 2);
71         }
72         stat->ip.input = input;
73         stat->ip.serial = 0;
74         RVM_CPUREG_SETL(stat->cpu, R_REC, 0);
75         RVM_CPUREG_SETU(stat->cpu, SP, 0);
76         RVM_CPUREG_SETU(stat->cpu, FP, 0);
77         RVM_CPUREG_SETU(stat->cpu, R_LOO, 0);
78         RVM_CPUREG_SETU(stat->cpu, R_TOP, -1);
79         if (stat->records) {
80                 RVM_CPUREG_SETL(stat->cpu, R_REC, (rlong)(r_array_length(stat->records) - 1));
81         }
82         return 0;
83 }
84
85
86 void rpa_stat_cacheinvalidate(rpastat_t *stat)
87 {
88         rpa_cache_invalidate(stat->cache);
89 }
90
91
92 rlong rpa_stat_exec(rpastat_t *stat, rvm_asmins_t *prog, rword off, ruint encoding, const rchar *input, const rchar *start, const rchar *end, rarray_t *records)
93 {
94         rlong ret;
95
96         if (!stat) {
97                 return -1;
98         }
99         rpa_stat_cacheinvalidate(stat);
100         rpa_stat_init(stat, encoding, input, start, end, records);
101
102         if (stat->debug) {
103                 ret = rvm_cpu_exec_debug(stat->cpu, prog, off);
104         } else {
105                 ret = rvm_cpu_exec(stat->cpu, prog, off);
106         }
107         if (ret < 0) {
108                 if (!stat->cpu->error) {
109                         if (stat->cpu->error) {
110                                 RPA_STAT_SETERROR_CODE(stat, stat->cpu->error);
111                         } else {
112                                 /*
113                                  * We should never get to here. Error have to be more
114                                  * specific and set at the places they are detected.
115                                  */
116                                 RPA_STAT_SETERROR_CODE(stat, RPA_E_EXECUTION);
117                         }
118                 }
119                 return -1;
120         }
121         ret = (rlong)RVM_CPUREG_GETL(stat->cpu, R0);
122         if (ret < 0) {
123                 return 0;
124         }
125         return ret;
126 }
127
128
129 static rlong rpa_stat_exec_rid(rpastat_t *stat, rparule_t rid, ruint encoding, const rchar *input, const rchar *start, const rchar *end, rarray_t *records)
130 {
131         rlong topsiz = 0;
132         rpainput_t *ptp;
133
134         if ((topsiz = rpa_stat_exec(stat, rpa_dbex_executable(stat->dbex), rpa_dbex_executableoffset(stat->dbex, rid), encoding, input, start, end, records)) < 0) {
135                 return -1;
136         }
137         if (topsiz <= 0)
138                 return 0;
139         ptp = &stat->instack[topsiz];
140         return (ptp->input - input);
141 }
142
143
144 rlong rpa_stat_scan(rpastat_t *stat, rparule_t rid, ruint encoding, const rchar *input, const rchar *start, const rchar *end, const rchar **where)
145 {
146         rlong ret;
147
148         while (input < end) {
149                 ret = rpa_stat_exec_rid(stat, rid, encoding, input, start, end, NULL);
150                 if (ret < 0)
151                         return -1;
152                 if (ret > 0) {
153                         *where = input;
154                         return ret;
155                 }
156                 input += 1;
157         }
158         return ret;
159 }
160
161
162 rlong rpa_stat_match(rpastat_t *stat, rparule_t rid, ruint encoding, const rchar *input, const rchar *start, const rchar *end)
163 {
164         return rpa_stat_exec_rid(stat, rid, encoding, input, start, end, NULL);
165 }
166
167
168 rlong rpa_stat_parse(rpastat_t *stat, rparule_t rid, ruint encoding, const rchar *input, const rchar *start, const rchar *end, rarray_t *records)
169 {
170         return rpa_stat_exec_rid(stat, rid, encoding, input, start, end, records);
171 }
172
173
174 rint rpa_stat_abort(rpastat_t *stat)
175 {
176         if (!stat) {
177                 return -1;
178         }
179         RPA_STAT_SETERROR_CODE(stat, RPA_E_USERABORT);
180         rvm_cpu_abort(stat->cpu);
181         return 0;
182 }
183
184
185 rint rpa_stat_matchchr(rpastat_t *stat, rssize_t top, rulong wc)
186 {
187         rint ret = 0;
188         rpainput_t *in = &stat->instack[top];
189
190         if (in->eof)
191                 return 0;
192         if (stat->encoding & RPA_ENCODING_ICASE) {
193                 ret = (in->wc == wc || in->iwc == wc) ? 1 : 0;
194         } else {
195                 ret = (in->wc == wc) ? 1 : 0;
196         }
197         return ret;
198 }
199
200
201 rint rpa_stat_matchspchr(rpastat_t *stat, rssize_t top, rulong wc)
202 {
203         rint ret = 0;
204         rpainput_t *in = &stat->instack[top];
205
206         if (in->eof)
207                 return 0;
208
209         switch (wc) {
210                 case '.':
211                         return 1;
212                         break;
213                 case 't':
214                         wc = '\t';
215                         break;
216                 case 'r':
217                         wc = '\r';
218                         break;
219                 case 'n':
220                         wc = '\n';
221                         break;
222                 default:
223                         break;
224         };
225
226         ret = (in->wc == wc) ? 1 : 0;
227         return ret;
228 }
229
230
231 rint rpa_stat_matchrng(rpastat_t *stat, rssize_t top, rulong wc1, rulong wc2)
232 {
233         rint ret = 0;
234         rpainput_t *in = &stat->instack[top];
235
236         if (in->eof)
237                 return 0;
238         if (stat->encoding & RPA_ENCODING_ICASE) {
239                 ret = ((in->wc >= wc1 && in->wc <= wc2) || (in->iwc >= wc1 && in->iwc <= wc2)) ? 1 : 0;
240         } else {
241                 ret = ((in->wc >= wc1 && in->wc <= wc2)) ? 1 : 0;
242         }
243         return ret;
244 }
245
246
247 static rint rpa_stat_utf8_getchar(ruint32 *pwc, rpastat_t *stat, const rchar *input)
248 {
249         return r_utf8_mbtowc(pwc, (const ruchar*)input, (const ruchar*)stat->end);
250 }
251
252
253 static rint rpa_stat_byte_getchar(ruint32 *pwc, rpastat_t *stat, const rchar *input)
254 {
255         if (input >= stat->end) {
256                 *pwc = (unsigned int)0;
257                 return 0;
258         }
259         *pwc = *((const ruchar*)input);
260         return 1;
261 }
262
263
264 static int rpa_stat_utf16_getchar(ruint32 *pwc, rpastat_t *stat, const rchar *input)
265 {
266         return r_utf16_mbtowc(pwc, (const ruchar*)input, (const ruchar*)stat->end);
267 }
268
269
270 rlong rpa_stat_shift(rpastat_t *stat, rssize_t top)
271 {
272         rpainput_t * ptp = &stat->instack[top];
273
274         if (ptp->eof)
275                 return -1;
276         ptp++;
277         top++;
278         if (top >= (rlong)stat->ip.serial) {
279                 rint inc = 0;
280                 ptp->input = stat->ip.input;
281                 if (ptp->input < stat->end) {
282                         switch (stat->encoding & RPA_ENCODING_MASK) {
283                         default:
284                         case RPA_ENCODING_UTF8:
285                                 inc = rpa_stat_utf8_getchar(&ptp->wc, stat, (const rchar*)stat->ip.input);
286                                 break;
287                         case RPA_ENCODING_UTF16LE:
288                                 inc = rpa_stat_utf16_getchar(&ptp->wc, stat, (const rchar*)stat->ip.input);
289                                 break;
290                         case RPA_ENCODING_BYTE:
291                                 inc = rpa_stat_byte_getchar(&ptp->wc, stat, (const rchar*)stat->ip.input);
292                                 break;
293                         };
294                         if (stat->encoding & RPA_ENCODING_ICASE)
295                                 ptp->iwc = r_charicase(ptp->wc);
296                         stat->ip.input += inc;
297                         stat->ip.serial += 1;
298                         ptp->eof = 0;
299                 } else {
300                         ptp->wc = (ruint32)-1;
301                         ptp->eof = 1;
302                 }
303         }
304
305         return top;
306 }
307
308
309 rlong rpa_stat_lasterror(rpastat_t *stat)
310 {
311         if (!stat)
312                 return -1;
313         return stat->err.code;
314 }
315
316
317 rlong rpa_stat_lasterrorinfo(rpastat_t *stat, rpa_errinfo_t *errinfo)
318 {
319         if (!stat || !errinfo)
320                 return -1;
321         r_memcpy(errinfo, &stat->err, sizeof(rpa_errinfo_t));
322         return 0;
323 }