Wireshark 4.5.0
The Wireshark network protocol analyzer
Loading...
Searching...
No Matches
algo.h
1/* algo.h */
2/* See Copyright Notice in the file LICENSE */
3/* SPDX-License-Identifier: MIT */
4
5#include "common.h"
6
7#define REX_VERSION "Lrexlib " VERSION
8
9/* Forward declarations */
10static void gmatch_pushsubject (lua_State *L, TArgExec *argE);
11static int findmatch_exec (TUserdata *ud, TArgExec *argE);
12static int split_exec (TUserdata *ud, TArgExec *argE, int offset);
13static int gsub_exec (TUserdata *ud, TArgExec *argE, int offset);
14static int gmatch_exec (TUserdata *ud, TArgExec *argE);
15static int compile_regex (lua_State *L, const TArgComp *argC, TUserdata **pud);
16static int generate_error (lua_State *L, const TUserdata *ud, int errcode);
17
18#if LUA_VERSION_NUM == 501
19# define ALG_ENVIRONINDEX LUA_ENVIRONINDEX
20#else
21# define ALG_ENVIRONINDEX lua_upvalueindex(1)
22#endif
23
24#ifndef ALG_CHARSIZE
25# define ALG_CHARSIZE 1
26#endif
27
28#ifndef BUFFERZ_PUTREPSTRING
29# define BUFFERZ_PUTREPSTRING bufferZ_putrepstring
30#endif
31
32#ifndef ALG_GETCARGS
33# define ALG_GETCARGS(a,b,c)
34#endif
35
36#ifndef DO_NAMED_SUBPATTERNS
37#define DO_NAMED_SUBPATTERNS(a,b,c)
38#endif
39
40#define METHOD_FIND 0
41#define METHOD_MATCH 1
42#define METHOD_EXEC 2
43#define METHOD_TFIND 3
44
45
46static int OptLimit (lua_State *L, int pos) {
47 if (lua_isnoneornil (L, pos))
48 return GSUB_UNLIMITED;
49 if (lua_isfunction (L, pos))
50 return GSUB_CONDITIONAL;
51 if (lua_isnumber (L, pos)) {
52 int a = lua_tointeger (L, pos);
53 return a < 0 ? 0 : a;
54 }
55 return luaL_typerror (L, pos, "number or function");
56}
57
58
59static int get_startoffset(lua_State *L, int stackpos, size_t len) {
60 int startoffset = (int)luaL_optinteger(L, stackpos, 1);
61 if(startoffset > 0)
62 startoffset--;
63 else if(startoffset < 0) {
64 startoffset += len/ALG_CHARSIZE;
65 if(startoffset < 0)
66 startoffset = 0;
67 }
68 return startoffset*ALG_CHARSIZE;
69}
70
71
72static TUserdata* test_ud (lua_State *L, int pos)
73{
74 TUserdata *ud;
75 if (lua_getmetatable(L, pos) &&
76 lua_rawequal(L, -1, ALG_ENVIRONINDEX) &&
77 (ud = (TUserdata *)lua_touserdata(L, pos)) != NULL) {
78 lua_pop(L, 1);
79 return ud;
80 }
81 return NULL;
82}
83
84
85static TUserdata* check_ud (lua_State *L)
86{
87 TUserdata *ud = test_ud(L, 1);
88 if (ud == NULL) luaL_typerror(L, 1, REX_TYPENAME);
89 return ud;
90}
91
92
93static void check_subject (lua_State *L, int pos, TArgExec *argE)
94{
95 int stype;
96 argE->text = lua_tolstring (L, pos, &argE->textlen);
97 stype = lua_type (L, pos);
98 if (stype != LUA_TSTRING && stype != LUA_TTABLE && stype != LUA_TUSERDATA) {
99 luaL_typerror (L, pos, "string, table or userdata");
100 } else if (argE->text == NULL) {
101 int type;
102 lua_getfield (L, pos, "topointer");
103 if (lua_type (L, -1) != LUA_TFUNCTION)
104 luaL_error (L, "subject has no topointer method");
105 lua_pushvalue (L, pos);
106 lua_call (L, 1, 1);
107 type = lua_type (L, -1);
108 if (type != LUA_TLIGHTUSERDATA)
109 luaL_error (L, "subject's topointer method returned %s (expected lightuserdata)",
110 lua_typename (L, type));
111 argE->text = (const char*) lua_touserdata (L, -1);
112 lua_pop (L, 1);
113#if LUA_VERSION_NUM == 501
114 if (luaL_callmeta (L, pos, "__len")) {
115 if (lua_type (L, -1) != LUA_TNUMBER)
116 luaL_argerror (L, pos, "subject's length is not a number");
117 argE->textlen = lua_tointeger (L, -1);
118 lua_pop (L, 1);
119 }
120 else
121 argE->textlen = lua_objlen (L, pos);
122#else
123 argE->textlen = luaL_len (L, pos);
124#endif
125 }
126}
127
128static void check_pattern (lua_State *L, int pos, TArgComp *argC)
129{
130 if (lua_isstring (L, pos)) {
131 argC->pattern = lua_tolstring (L, pos, &argC->patlen);
132 argC->ud = NULL;
133 }
134 else if ((argC->ud = test_ud (L, pos)) == NULL)
135 luaL_typerror(L, pos, "string or " REX_TYPENAME);
136}
137
138static void checkarg_new (lua_State *L, TArgComp *argC) {
139 argC->pattern = luaL_checklstring (L, 1, &argC->patlen);
140 argC->cflags = ALG_GETCFLAGS (L, 2);
141 ALG_GETCARGS (L, 3, argC);
142}
143
144
145/* function gsub (s, patt, f, [n], [cf], [ef], [larg...]) */
146static void checkarg_gsub (lua_State *L, TArgComp *argC, TArgExec *argE) {
147 check_subject (L, 1, argE);
148 check_pattern (L, 2, argC);
149 lua_tostring (L, 3); /* converts number (if any) to string */
150 argE->reptype = lua_type (L, 3);
151 if (argE->reptype != LUA_TSTRING && argE->reptype != LUA_TTABLE &&
152 argE->reptype != LUA_TFUNCTION) {
153 luaL_typerror (L, 3, "string, table or function");
154 }
155 argE->funcpos = 3;
156 argE->funcpos2 = 4;
157 argE->maxmatch = OptLimit (L, 4);
158 argC->cflags = ALG_GETCFLAGS (L, 5);
159 argE->eflags = (int)luaL_optinteger (L, 6, ALG_EFLAGS_DFLT);
160 ALG_GETCARGS (L, 7, argC);
161}
162
163
164/* function count (s, patt, [cf], [ef], [larg...]) */
165static void checkarg_count (lua_State *L, TArgComp *argC, TArgExec *argE) {
166 check_subject (L, 1, argE);
167 check_pattern (L, 2, argC);
168 argC->cflags = ALG_GETCFLAGS (L, 3);
169 argE->eflags = (int)luaL_optinteger (L, 4, ALG_EFLAGS_DFLT);
170 ALG_GETCARGS (L, 5, argC);
171}
172
173
174/* function find (s, patt, [st], [cf], [ef], [larg...]) */
175/* function match (s, patt, [st], [cf], [ef], [larg...]) */
176static void checkarg_find_func (lua_State *L, TArgComp *argC, TArgExec *argE) {
177 check_subject (L, 1, argE);
178 check_pattern (L, 2, argC);
179 argE->startoffset = get_startoffset (L, 3, argE->textlen);
180 argC->cflags = ALG_GETCFLAGS (L, 4);
181 argE->eflags = (int)luaL_optinteger (L, 5, ALG_EFLAGS_DFLT);
182 ALG_GETCARGS (L, 6, argC);
183}
184
185
186/* function gmatch (s, patt, [cf], [ef], [larg...]) */
187/* function split (s, patt, [cf], [ef], [larg...]) */
188static void checkarg_gmatch_split (lua_State *L, TArgComp *argC, TArgExec *argE) {
189 check_subject (L, 1, argE);
190 check_pattern (L, 2, argC);
191 argC->cflags = ALG_GETCFLAGS (L, 3);
192 argE->eflags = (int)luaL_optinteger (L, 4, ALG_EFLAGS_DFLT);
193 ALG_GETCARGS (L, 5, argC);
194}
195
196
197/* method r:tfind (s, [st], [ef]) */
198/* method r:exec (s, [st], [ef]) */
199/* method r:find (s, [st], [ef]) */
200/* method r:match (s, [st], [ef]) */
201static void checkarg_find_method (lua_State *L, TArgExec *argE, TUserdata **ud) {
202 *ud = check_ud (L);
203 check_subject (L, 2, argE);
204 argE->startoffset = get_startoffset (L, 3, argE->textlen);
205 argE->eflags = (int)luaL_optinteger (L, 4, ALG_EFLAGS_DFLT);
206}
207
208
209static int algf_new (lua_State *L) {
210 TArgComp argC;
211 checkarg_new (L, &argC);
212 return compile_regex (L, &argC, NULL);
213}
214
215static void push_substrings (lua_State *L, TUserdata *ud, const char *text,
216 TFreeList *freelist) {
217 int i;
218 if (lua_checkstack (L, ALG_NSUB(ud)) == 0) {
219 if (freelist)
220 freelist_free (freelist);
221 luaL_error (L, "cannot add %d stack slots", ALG_NSUB(ud));
222 }
223 for (i = 1; i <= ALG_NSUB(ud); i++) {
224 ALG_PUSHSUB_OR_FALSE (L, ud, text, i);
225 }
226}
227
228static int algf_gsub (lua_State *L) {
229 TUserdata *ud;
230 TArgComp argC;
231 TArgExec argE;
232 int n_match = 0, n_subst = 0, st = 0, last_to = -1;
233 TBuffer BufOut, BufRep, BufTemp, *pBuf = &BufOut;
234 TFreeList freelist;
235 /*------------------------------------------------------------------*/
236 checkarg_gsub (L, &argC, &argE);
237 if (argC.ud) {
238 ud = (TUserdata*) argC.ud;
239 lua_pushvalue (L, 2);
240 }
241 else compile_regex (L, &argC, &ud);
242 freelist_init (&freelist);
243 /*------------------------------------------------------------------*/
244 if (argE.reptype == LUA_TSTRING) {
245 buffer_init (&BufRep, 256, L, &freelist);
246 BUFFERZ_PUTREPSTRING (&BufRep, argE.funcpos, ALG_NSUB(ud));
247 }
248 /*------------------------------------------------------------------*/
249 if (argE.maxmatch == GSUB_CONDITIONAL) {
250 buffer_init (&BufTemp, 1024, L, &freelist);
251 pBuf = &BufTemp;
252 }
253 /*------------------------------------------------------------------*/
254 buffer_init (&BufOut, 1024, L, &freelist);
255 while ((argE.maxmatch < 0 || n_match < argE.maxmatch) && st <= (int)argE.textlen) {
256 int from, to, res;
257 int curr_subst = 0;
258 res = gsub_exec (ud, &argE, st);
259 if (ALG_NOMATCH (res)) {
260 break;
261 }
262 else if (!ALG_ISMATCH (res)) {
263 freelist_free (&freelist);
264 return generate_error (L, ud, res);
265 }
266 from = ALG_BASE(st) + ALG_SUBBEG(ud,0);
267 to = ALG_BASE(st) + ALG_SUBEND(ud,0);
268 if (to == last_to) { /* discard an empty match adjacent to the previous match */
269 if (st < (int)argE.textlen) { /* advance by 1 char (not replaced) */
270 buffer_addlstring (&BufOut, argE.text + st, ALG_CHARSIZE);
271 st += ALG_CHARSIZE;
272 continue;
273 }
274 break;
275 }
276 last_to = to;
277 ++n_match;
278 if (st < from) {
279 buffer_addlstring (&BufOut, argE.text + st, from - st);
280#ifdef ALG_PULL
281 st = from;
282#endif
283 }
284 /*----------------------------------------------------------------*/
285 if (argE.reptype == LUA_TSTRING) {
286 size_t iter = 0, num;
287 const char *str;
288 while (bufferZ_next (&BufRep, &iter, &num, &str)) {
289 if (str)
290 buffer_addlstring (pBuf, str, num);
291 else if (num == 0 || ALG_SUBVALID (ud,num))
292 buffer_addlstring (pBuf, argE.text + ALG_BASE(st) + ALG_SUBBEG(ud,num), ALG_SUBLEN(ud,num));
293 }
294 curr_subst = 1;
295 }
296 /*----------------------------------------------------------------*/
297 else if (argE.reptype == LUA_TTABLE) {
298 if (ALG_NSUB(ud) > 0)
299 ALG_PUSHSUB_OR_FALSE (L, ud, argE.text + ALG_BASE(st), 1);
300 else
301 lua_pushlstring (L, argE.text + from, to - from);
302 lua_gettable (L, argE.funcpos);
303 }
304 /*----------------------------------------------------------------*/
305 else if (argE.reptype == LUA_TFUNCTION) {
306 int narg;
307 lua_pushvalue (L, argE.funcpos);
308 if (ALG_NSUB(ud) > 0) {
309 push_substrings (L, ud, argE.text + ALG_BASE(st), &freelist);
310 narg = ALG_NSUB(ud);
311 }
312 else {
313 lua_pushlstring (L, argE.text + from, to - from);
314 narg = 1;
315 }
316 if (0 != lua_pcall (L, narg, 1, 0)) {
317 freelist_free (&freelist);
318 return lua_error (L); /* re-raise the error */
319 }
320 }
321 /*----------------------------------------------------------------*/
322 if (argE.reptype == LUA_TTABLE || argE.reptype == LUA_TFUNCTION) {
323 if (lua_tostring (L, -1)) {
324 buffer_addvalue (pBuf, -1);
325 curr_subst = 1;
326 }
327 else if (!lua_toboolean (L, -1))
328 buffer_addlstring (pBuf, argE.text + from, to - from);
329 else {
330 freelist_free (&freelist);
331 luaL_error (L, "invalid replacement value (a %s)", luaL_typename (L, -1));
332 }
333 if (argE.maxmatch != GSUB_CONDITIONAL)
334 lua_pop (L, 1);
335 }
336 /*----------------------------------------------------------------*/
337 if (argE.maxmatch == GSUB_CONDITIONAL) {
338 /* Call the function */
339 lua_pushvalue (L, argE.funcpos2);
340 lua_pushinteger (L, from/ALG_CHARSIZE + 1);
341 lua_pushinteger (L, to/ALG_CHARSIZE);
342 if (argE.reptype == LUA_TSTRING)
343 buffer_pushresult (&BufTemp);
344 else {
345 lua_pushvalue (L, -4);
346 lua_remove (L, -5);
347 }
348 if (0 != lua_pcall (L, 3, 2, 0)) {
349 freelist_free (&freelist);
350 lua_error (L); /* re-raise the error */
351 }
352 /* Handle the 1-st return value */
353 if (lua_isstring (L, -2)) { /* coercion is allowed here */
354 buffer_addvalue (&BufOut, -2); /* rep2 */
355 curr_subst = 1;
356 }
357 else if (lua_toboolean (L, -2))
358 buffer_addbuffer (&BufOut, &BufTemp); /* rep1 */
359 else {
360 buffer_addlstring (&BufOut, argE.text + from, to - from); /* "no" */
361 curr_subst = 0;
362 }
363 /* Handle the 2-nd return value */
364 if (lua_type (L, -1) == LUA_TNUMBER) { /* no coercion is allowed here */
365 int n = lua_tointeger (L, -1);
366 if (n < 0) /* n */
367 n = 0;
368 argE.maxmatch = n_match + n;
369 }
370 else if (lua_toboolean (L, -1)) /* "yes to all" */
371 argE.maxmatch = GSUB_UNLIMITED;
372 else
373 buffer_clear (&BufTemp);
374
375 lua_pop (L, 2);
376 if (argE.maxmatch != GSUB_CONDITIONAL)
377 pBuf = &BufOut;
378 }
379 /*----------------------------------------------------------------*/
380 n_subst += curr_subst;
381 if (st < to) {
382 st = to;
383 }
384 else if (st < (int)argE.textlen) {
385 /* advance by 1 char (not replaced) */
386 buffer_addlstring (&BufOut, argE.text + st, ALG_CHARSIZE);
387 st += ALG_CHARSIZE;
388 }
389 else break;
390 }
391 /*------------------------------------------------------------------*/
392 buffer_addlstring (&BufOut, argE.text + st, argE.textlen - st);
393 buffer_pushresult (&BufOut);
394 lua_pushinteger (L, n_match);
395 lua_pushinteger (L, n_subst);
396 freelist_free (&freelist);
397 return 3;
398}
399
400
401static int algf_count (lua_State *L) {
402 TUserdata *ud;
403 TArgComp argC;
404 TArgExec argE;
405 int n_match = 0, st = 0, last_to = -1;
406 /*------------------------------------------------------------------*/
407 checkarg_count (L, &argC, &argE);
408 if (argC.ud) {
409 ud = (TUserdata*) argC.ud;
410 lua_pushvalue (L, 2);
411 }
412 else compile_regex (L, &argC, &ud);
413 /*------------------------------------------------------------------*/
414 while (st <= (int)argE.textlen) {
415 int to, res;
416 res = gsub_exec (ud, &argE, st);
417 if (ALG_NOMATCH (res)) {
418 break;
419 }
420 else if (!ALG_ISMATCH (res)) {
421 return generate_error (L, ud, res);
422 }
423 to = ALG_BASE(st) + ALG_SUBEND(ud,0);
424 if (to == last_to) { /* discard an empty match adjacent to the previous match */
425 if (st < (int)argE.textlen) { /* advance by 1 char */
426 st += ALG_CHARSIZE;
427 continue;
428 }
429 break;
430 }
431 last_to = to;
432 ++n_match;
433#ifdef ALG_PULL
434 {
435 int from = ALG_BASE(st) + ALG_SUBBEG(ud,0);
436 if (st < from)
437 st = from;
438 }
439#endif
440 /*----------------------------------------------------------------*/
441 if (st < to) {
442 st = to;
443 }
444 else if (st < (int)argE.textlen) {
445 /* advance by 1 char (not replaced) */
446 st += ALG_CHARSIZE;
447 }
448 else break;
449 }
450 /*------------------------------------------------------------------*/
451 lua_pushinteger (L, n_match);
452 return 1;
453}
454
455
456static int finish_generic_find (lua_State *L, TUserdata *ud, TArgExec *argE,
457 int method, int res)
458{
459 if (ALG_ISMATCH (res)) {
460 if (method == METHOD_FIND)
461 ALG_PUSHOFFSETS (L, ud, ALG_BASE(argE->startoffset), 0);
462 if (ALG_NSUB(ud)) /* push captures */
463 push_substrings (L, ud, argE->text, NULL);
464 else if (method != METHOD_FIND) {
465 ALG_PUSHSUB (L, ud, argE->text, 0);
466 return 1;
467 }
468 return (method == METHOD_FIND) ? ALG_NSUB(ud) + 2 : ALG_NSUB(ud);
469 }
470 else if (ALG_NOMATCH (res))
471 return lua_pushnil (L), 1;
472 else
473 return generate_error (L, ud, res);
474}
475
476
477static int generic_find_func (lua_State *L, int method) {
478 TUserdata *ud;
479 TArgComp argC;
480 TArgExec argE;
481 int res;
482
483 checkarg_find_func (L, &argC, &argE);
484 if (argE.startoffset > (int)argE.textlen)
485 return lua_pushnil (L), 1;
486
487 if (argC.ud) {
488 ud = (TUserdata*) argC.ud;
489 lua_pushvalue (L, 2);
490 }
491 else compile_regex (L, &argC, &ud);
492 res = findmatch_exec (ud, &argE);
493 return finish_generic_find (L, ud, &argE, method, res);
494}
495
496
497static int algf_find (lua_State *L) {
498 return generic_find_func (L, METHOD_FIND);
499}
500
501
502static int algf_match (lua_State *L) {
503 return generic_find_func (L, METHOD_MATCH);
504}
505
506
507static int gmatch_iter (lua_State *L) {
508 int last_end, res;
509 TArgExec argE;
510 TUserdata *ud = (TUserdata*) lua_touserdata (L, lua_upvalueindex (1));
511 argE.text = lua_tolstring (L, lua_upvalueindex (2), &argE.textlen);
512 argE.eflags = lua_tointeger (L, lua_upvalueindex (3));
513 argE.startoffset = lua_tointeger (L, lua_upvalueindex (4));
514 last_end = lua_tointeger (L, lua_upvalueindex (5));
515
516 while (1) {
517 if (argE.startoffset > (int)argE.textlen)
518 return 0;
519 res = gmatch_exec (ud, &argE);
520 if (ALG_ISMATCH (res)) {
521 int incr = 0;
522 if (!ALG_SUBLEN(ud,0)) { /* no progress: prevent endless loop */
523 if (last_end == ALG_BASE(argE.startoffset) + ALG_SUBEND(ud,0)) {
524 argE.startoffset += ALG_CHARSIZE;
525 continue;
526 }
527 incr = ALG_CHARSIZE;
528 }
529 last_end = ALG_BASE(argE.startoffset) + ALG_SUBEND(ud,0);
530 lua_pushinteger(L, last_end + incr); /* update start offset */
531 lua_replace (L, lua_upvalueindex (4));
532 lua_pushinteger(L, last_end); /* update last end of match */
533 lua_replace (L, lua_upvalueindex (5));
534 /* push either captures or entire match */
535 if (ALG_NSUB(ud)) {
536 push_substrings (L, ud, argE.text, NULL);
537 return ALG_NSUB(ud);
538 }
539 else {
540 ALG_PUSHSUB (L, ud, argE.text, 0);
541 return 1;
542 }
543 }
544 else if (ALG_NOMATCH (res))
545 return 0;
546 else
547 return generate_error (L, ud, res);
548 }
549}
550
551
552static int split_iter (lua_State *L) {
553 int incr, last_end, newoffset, res;
554 TArgExec argE;
555 TUserdata *ud = (TUserdata*) lua_touserdata (L, lua_upvalueindex (1));
556 argE.text = lua_tolstring (L, lua_upvalueindex (2), &argE.textlen);
557 argE.eflags = lua_tointeger (L, lua_upvalueindex (3));
558 argE.startoffset = lua_tointeger (L, lua_upvalueindex (4));
559 incr = lua_tointeger (L, lua_upvalueindex (5));
560 last_end = lua_tointeger (L, lua_upvalueindex (6));
561
562 if (incr < 0)
563 return 0;
564
565 while (1) {
566 if ((newoffset = argE.startoffset + incr) > (int)argE.textlen)
567 break;
568 res = split_exec (ud, &argE, newoffset);
569 if (ALG_ISMATCH (res)) {
570 if (!ALG_SUBLEN(ud,0)) { /* no progress: prevent endless loop */
571 if (last_end == ALG_BASE(argE.startoffset) + ALG_SUBEND(ud,0)) {
572 incr += ALG_CHARSIZE;
573 continue;
574 }
575 }
576 lua_pushinteger(L, ALG_BASE(newoffset) + ALG_SUBEND(ud,0)); /* update start offset and last_end */
577 lua_pushvalue (L, -1);
578 lua_replace (L, lua_upvalueindex (4));
579 lua_replace (L, lua_upvalueindex (6));
580 lua_pushinteger (L, ALG_SUBLEN(ud,0) ? 0 : ALG_CHARSIZE); /* update incr */
581 lua_replace (L, lua_upvalueindex (5));
582 /* push text preceding the match */
583 lua_pushlstring (L, argE.text + argE.startoffset,
584 ALG_SUBBEG(ud,0) + ALG_BASE(newoffset) - argE.startoffset);
585 /* push either captures or entire match */
586 if (ALG_NSUB(ud)) {
587 push_substrings (L, ud, argE.text + ALG_BASE(newoffset), NULL);
588 return 1 + ALG_NSUB(ud);
589 }
590 else {
591 ALG_PUSHSUB (L, ud, argE.text + ALG_BASE(newoffset), 0);
592 return 2;
593 }
594 }
595 else if (ALG_NOMATCH (res))
596 break;
597 else
598 return generate_error (L, ud, res);
599 }
600 lua_pushinteger (L, -1); /* mark as last iteration */
601 lua_replace (L, lua_upvalueindex (5)); /* incr = -1 */
602 lua_pushlstring (L, argE.text+argE.startoffset, argE.textlen-argE.startoffset);
603 return 1;
604}
605
606
607static int algf_gmatch (lua_State *L)
608{
609 TArgComp argC;
610 TArgExec argE;
611 checkarg_gmatch_split (L, &argC, &argE);
612 if (argC.ud)
613 lua_pushvalue (L, 2);
614 else
615 compile_regex (L, &argC, NULL); /* 1-st upvalue: ud */
616 gmatch_pushsubject (L, &argE); /* 2-nd upvalue: s */
617 lua_pushinteger (L, argE.eflags); /* 3-rd upvalue: ef */
618 lua_pushinteger (L, 0); /* 4-th upvalue: startoffset */
619 lua_pushinteger (L, -1); /* 5-th upvalue: last end of match */
620 lua_pushcclosure (L, gmatch_iter, 5);
621 return 1;
622}
623
624static int algf_split (lua_State *L)
625{
626 TArgComp argC;
627 TArgExec argE;
628 checkarg_gmatch_split (L, &argC, &argE);
629 if (argC.ud)
630 lua_pushvalue (L, 2);
631 else
632 compile_regex (L, &argC, NULL); /* 1-st upvalue: ud */
633 gmatch_pushsubject (L, &argE); /* 2-nd upvalue: s */
634 lua_pushinteger (L, argE.eflags); /* 3-rd upvalue: ef */
635 lua_pushinteger (L, 0); /* 4-th upvalue: startoffset */
636 lua_pushinteger (L, 0); /* 5-th upvalue: incr */
637 lua_pushinteger (L, -1); /* 6-th upvalue: last_end */
638 lua_pushcclosure (L, split_iter, 6);
639 return 1;
640}
641
642
643static void push_substring_table (lua_State *L, TUserdata *ud, const char *text) {
644 int i;
645 lua_newtable (L);
646 for (i = 1; i <= ALG_NSUB(ud); i++) {
647 ALG_PUSHSUB_OR_FALSE (L, ud, text, i);
648 lua_rawseti (L, -2, i);
649 }
650}
651
652
653static void push_offset_table (lua_State *L, TUserdata *ud, int startoffset) {
654 int i, j;
655 lua_newtable (L);
656 for (i=1, j=1; i <= ALG_NSUB(ud); i++) {
657 if (ALG_SUBVALID (ud,i)) {
658 ALG_PUSHSTART (L, ud, startoffset, i);
659 lua_rawseti (L, -2, j++);
660 ALG_PUSHEND (L, ud, startoffset, i);
661 lua_rawseti (L, -2, j++);
662 }
663 else {
664 lua_pushboolean (L, 0);
665 lua_rawseti (L, -2, j++);
666 lua_pushboolean (L, 0);
667 lua_rawseti (L, -2, j++);
668 }
669 }
670}
671
672
673static int generic_find_method (lua_State *L, int method) {
674 TUserdata *ud;
675 TArgExec argE;
676 int res;
677
678 checkarg_find_method (L, &argE, &ud);
679 if (argE.startoffset > (int)argE.textlen)
680 return lua_pushnil(L), 1;
681
682 res = findmatch_exec (ud, &argE);
683 if (ALG_ISMATCH (res)) {
684 switch (method) {
685 case METHOD_EXEC:
686 ALG_PUSHOFFSETS (L, ud, ALG_BASE(argE.startoffset), 0);
687 push_offset_table (L, ud, ALG_BASE(argE.startoffset));
688 DO_NAMED_SUBPATTERNS (L, ud, argE.text);
689 return 3;
690 case METHOD_TFIND:
691 ALG_PUSHOFFSETS (L, ud, ALG_BASE(argE.startoffset), 0);
692 push_substring_table (L, ud, argE.text);
693 DO_NAMED_SUBPATTERNS (L, ud, argE.text);
694 return 3;
695 case METHOD_MATCH:
696 case METHOD_FIND:
697 return finish_generic_find (L, ud, &argE, method, res);
698 }
699 return 0;
700 }
701 else if (ALG_NOMATCH (res))
702 return lua_pushnil (L), 1;
703 else
704 return generate_error(L, ud, res);
705}
706
707
708static int algm_find (lua_State *L) {
709 return generic_find_method (L, METHOD_FIND);
710}
711static int algm_match (lua_State *L) {
712 return generic_find_method (L, METHOD_MATCH);
713}
714static int algm_tfind (lua_State *L) {
715 return generic_find_method (L, METHOD_TFIND);
716}
717static int algm_exec (lua_State *L) {
718 return generic_find_method (L, METHOD_EXEC);
719}
720
721static void alg_register (lua_State *L, const luaL_Reg *r_methods,
722 const luaL_Reg *r_functions, const char *name) {
723 /* Create a new function environment to serve as a metatable for methods. */
724#if LUA_VERSION_NUM == 501
725 lua_newtable (L);
726 lua_pushvalue (L, -1);
727 lua_replace (L, LUA_ENVIRONINDEX);
728 luaL_register (L, NULL, r_methods);
729#else
730 luaL_newmetatable(L, REX_TYPENAME);
731 lua_pushvalue(L, -1);
732 luaL_setfuncs (L, r_methods, 1);
733#endif
734 lua_pushvalue(L, -1); /* mt.__index = mt */
735 lua_setfield(L, -2, "__index");
736
737 /* Register functions. */
738 lua_createtable(L, 0, 8);
739#if LUA_VERSION_NUM == 501
740 luaL_register (L, NULL, r_functions);
741#else
742 lua_pushvalue(L, -2);
743 luaL_setfuncs (L, r_functions, 1);
744#endif
745#ifdef REX_CREATEGLOBALVAR
746 lua_pushvalue(L, -1);
747 lua_setglobal(L, REX_LIBNAME);
748#endif
749 lua_pushfstring (L, REX_VERSION" (for %s)", name);
750 lua_setfield (L, -2, "_VERSION");
751#ifndef REX_NOEMBEDDEDTEST
752 lua_pushcfunction (L, newmembuffer);
753 lua_setfield (L, -2, "_newmembuffer");
754#endif
755}
Definition common.h:33
Definition common.h:46
Definition common.h:61
Definition common.h:69