Wireshark 4.7.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);
11
19static int findmatch_exec (TUserdata *ud, TArgExec *argE);
20
29static int split_exec (TUserdata *ud, TArgExec *argE, int offset);
30
39static int gsub_exec (TUserdata *ud, TArgExec *argE, int offset);
40
48static int gmatch_exec (TUserdata *ud, TArgExec *argE);
49
58static int compile_regex (lua_State *L, const TArgComp *argC, TUserdata **pud);
59
68static int generate_error (lua_State *L, const TUserdata *ud, int errcode);
69
70#if LUA_VERSION_NUM == 501
71# define ALG_ENVIRONINDEX LUA_ENVIRONINDEX
72#else
73# define ALG_ENVIRONINDEX lua_upvalueindex(1)
74#endif
75
76#ifndef ALG_CHARSIZE
77# define ALG_CHARSIZE 1
78#endif
79
80#ifndef BUFFERZ_PUTREPSTRING
81# define BUFFERZ_PUTREPSTRING bufferZ_putrepstring
82#endif
83
84#ifndef ALG_GETCARGS
85# define ALG_GETCARGS(a,b,c)
86#endif
87
88#ifndef DO_NAMED_SUBPATTERNS
89#define DO_NAMED_SUBPATTERNS(a,b,c)
90#endif
91
92#define METHOD_FIND 0
93#define METHOD_MATCH 1
94#define METHOD_EXEC 2
95#define METHOD_TFIND 3
96
97
110static int OptLimit (lua_State *L, int pos) {
111 if (lua_isnoneornil (L, pos))
112 return GSUB_UNLIMITED;
113 if (lua_isfunction (L, pos))
114 return GSUB_CONDITIONAL;
115 if (lua_isnumber (L, pos)) {
116 int a = lua_tointeger (L, pos);
117 return a < 0 ? 0 : a;
118 }
119 return luaL_typerror (L, pos, "number or function");
120}
121
122
135static int get_startoffset(lua_State *L, int stackpos, size_t len) {
136 int startoffset = (int)luaL_optinteger(L, stackpos, 1);
137 if(startoffset > 0)
138 startoffset--;
139 else if(startoffset < 0) {
140 startoffset += len/ALG_CHARSIZE;
141 if(startoffset < 0)
142 startoffset = 0;
143 }
144 return startoffset*ALG_CHARSIZE;
145}
146
147
158static TUserdata* test_ud (lua_State *L, int pos)
159{
160 TUserdata *ud;
161 if (lua_getmetatable(L, pos) &&
162 lua_rawequal(L, -1, ALG_ENVIRONINDEX) &&
163 (ud = (TUserdata *)lua_touserdata(L, pos)) != NULL) {
164 lua_pop(L, 1);
165 return ud;
166 }
167 return NULL;
168}
169
170
179static TUserdata* check_ud (lua_State *L)
180{
181 TUserdata *ud = test_ud(L, 1);
182 if (ud == NULL) luaL_typerror(L, 1, REX_TYPENAME);
183 return ud;
184}
185
186
194static void check_subject (lua_State *L, int pos, TArgExec *argE)
195{
196 int stype;
197 argE->text = lua_tolstring (L, pos, &argE->textlen);
198 stype = lua_type (L, pos);
199 if (stype != LUA_TSTRING && stype != LUA_TTABLE && stype != LUA_TUSERDATA) {
200 luaL_typerror (L, pos, "string, table or userdata");
201 } else if (argE->text == NULL) {
202 int type;
203 lua_getfield (L, pos, "topointer");
204 if (lua_type (L, -1) != LUA_TFUNCTION)
205 luaL_error (L, "subject has no topointer method");
206 lua_pushvalue (L, pos);
207 lua_call (L, 1, 1);
208 type = lua_type (L, -1);
209 if (type != LUA_TLIGHTUSERDATA)
210 luaL_error (L, "subject's topointer method returned %s (expected lightuserdata)",
211 lua_typename (L, type));
212 argE->text = (const char*) lua_touserdata (L, -1);
213 lua_pop (L, 1);
214#if LUA_VERSION_NUM == 501
215 if (luaL_callmeta (L, pos, "__len")) {
216 if (lua_type (L, -1) != LUA_TNUMBER)
217 luaL_argerror (L, pos, "subject's length is not a number");
218 argE->textlen = lua_tointeger (L, -1);
219 lua_pop (L, 1);
220 }
221 else
222 argE->textlen = lua_objlen (L, pos);
223#else
224 argE->textlen = luaL_len (L, pos);
225#endif
226 }
227}
228
240static void check_pattern (lua_State *L, int pos, TArgComp *argC)
241{
242 if (lua_isstring (L, pos)) {
243 argC->pattern = lua_tolstring (L, pos, &argC->patlen);
244 argC->ud = NULL;
245 }
246 else if ((argC->ud = test_ud (L, pos)) == NULL)
247 luaL_typerror(L, pos, "string or " REX_TYPENAME);
248}
249
258static void checkarg_new (lua_State *L, TArgComp *argC) {
259 argC->pattern = luaL_checklstring (L, 1, &argC->patlen);
260 argC->cflags = ALG_GETCFLAGS (L, 2);
261 ALG_GETCARGS (L, 3, argC);
262}
263
264
265/* function gsub (s, patt, f, [n], [cf], [ef], [larg...]) */
266
276static void checkarg_gsub (lua_State *L, TArgComp *argC, TArgExec *argE) {
277 check_subject (L, 1, argE);
278 check_pattern (L, 2, argC);
279 lua_tostring (L, 3); /* converts number (if any) to string */
280 argE->reptype = lua_type (L, 3);
281 if (argE->reptype != LUA_TSTRING && argE->reptype != LUA_TTABLE &&
282 argE->reptype != LUA_TFUNCTION) {
283 luaL_typerror (L, 3, "string, table or function");
284 }
285 argE->funcpos = 3;
286 argE->funcpos2 = 4;
287 argE->maxmatch = OptLimit (L, 4);
288 argC->cflags = ALG_GETCFLAGS (L, 5);
289 argE->eflags = (int)luaL_optinteger (L, 6, ALG_EFLAGS_DFLT);
290 ALG_GETCARGS (L, 7, argC);
291}
292
293
294/* function count (s, patt, [cf], [ef], [larg...]) */
295
306static void checkarg_count (lua_State *L, TArgComp *argC, TArgExec *argE) {
307 check_subject (L, 1, argE);
308 check_pattern (L, 2, argC);
309 argC->cflags = ALG_GETCFLAGS (L, 3);
310 argE->eflags = (int)luaL_optinteger (L, 4, ALG_EFLAGS_DFLT);
311 ALG_GETCARGS (L, 5, argC);
312}
313
314
315/* function find (s, patt, [st], [cf], [ef], [larg...]) */
316/* function match (s, patt, [st], [cf], [ef], [larg...]) */
317
327static void checkarg_find_func (lua_State *L, TArgComp *argC, TArgExec *argE) {
328 check_subject (L, 1, argE);
329 check_pattern (L, 2, argC);
330 argE->startoffset = get_startoffset (L, 3, argE->textlen);
331 argC->cflags = ALG_GETCFLAGS (L, 4);
332 argE->eflags = (int)luaL_optinteger (L, 5, ALG_EFLAGS_DFLT);
333 ALG_GETCARGS (L, 6, argC);
334}
335
336
337/* function gmatch (s, patt, [cf], [ef], [larg...]) */
338/* function split (s, patt, [cf], [ef], [larg...]) */
339
349static void checkarg_gmatch_split (lua_State *L, TArgComp *argC, TArgExec *argE) {
350 check_subject (L, 1, argE);
351 check_pattern (L, 2, argC);
352 argC->cflags = ALG_GETCFLAGS (L, 3);
353 argE->eflags = (int)luaL_optinteger (L, 4, ALG_EFLAGS_DFLT);
354 ALG_GETCARGS (L, 5, argC);
355}
356
357
358/* method r:tfind (s, [st], [ef]) */
359/* method r:exec (s, [st], [ef]) */
360/* method r:find (s, [st], [ef]) */
361/* method r:match (s, [st], [ef]) */
362
372static void checkarg_find_method (lua_State *L, TArgExec *argE, TUserdata **ud) {
373 *ud = check_ud (L);
374 check_subject (L, 2, argE);
375 argE->startoffset = get_startoffset (L, 3, argE->textlen);
376 argE->eflags = (int)luaL_optinteger (L, 4, ALG_EFLAGS_DFLT);
377}
378
379
388static int algf_new (lua_State *L) {
389 TArgComp argC;
390 checkarg_new (L, &argC);
391 return compile_regex (L, &argC, NULL);
392}
393
406static void push_substrings (lua_State *L, TUserdata *ud, const char *text,
407 TFreeList *freelist) {
408 int i;
409 if (lua_checkstack (L, ALG_NSUB(ud)) == 0) {
410 if (freelist)
411 freelist_free (freelist);
412 luaL_error (L, "cannot add %d stack slots", ALG_NSUB(ud));
413 }
414 for (i = 1; i <= ALG_NSUB(ud); i++) {
415 ALG_PUSHSUB_OR_FALSE (L, ud, text, i);
416 }
417}
418
428static int algf_gsub (lua_State *L) {
429 TUserdata *ud;
430 TArgComp argC;
431 TArgExec argE;
432 int n_match = 0, n_subst = 0, st = 0, last_to = -1;
433 TBuffer BufOut, BufRep, BufTemp, *pBuf = &BufOut;
434 TFreeList freelist;
435 /*------------------------------------------------------------------*/
436 checkarg_gsub (L, &argC, &argE);
437 if (argC.ud) {
438 ud = (TUserdata*) argC.ud;
439 lua_pushvalue (L, 2);
440 }
441 else compile_regex (L, &argC, &ud);
442 freelist_init (&freelist);
443 /*------------------------------------------------------------------*/
444 if (argE.reptype == LUA_TSTRING) {
445 buffer_init (&BufRep, 256, L, &freelist);
446 BUFFERZ_PUTREPSTRING (&BufRep, argE.funcpos, ALG_NSUB(ud));
447 }
448 /*------------------------------------------------------------------*/
449 if (argE.maxmatch == GSUB_CONDITIONAL) {
450 buffer_init (&BufTemp, 1024, L, &freelist);
451 pBuf = &BufTemp;
452 }
453 /*------------------------------------------------------------------*/
454 buffer_init (&BufOut, 1024, L, &freelist);
455 while ((argE.maxmatch < 0 || n_match < argE.maxmatch) && st <= (int)argE.textlen) {
456 int from, to, res;
457 int curr_subst = 0;
458 res = gsub_exec (ud, &argE, st);
459 if (ALG_NOMATCH (res)) {
460 break;
461 }
462 else if (!ALG_ISMATCH (res)) {
463 freelist_free (&freelist);
464 return generate_error (L, ud, res);
465 }
466 from = ALG_BASE(st) + ALG_SUBBEG(ud,0);
467 to = ALG_BASE(st) + ALG_SUBEND(ud,0);
468 if (to == last_to) { /* discard an empty match adjacent to the previous match */
469 if (st < (int)argE.textlen) { /* advance by 1 char (not replaced) */
470 buffer_addlstring (&BufOut, argE.text + st, ALG_CHARSIZE);
471 st += ALG_CHARSIZE;
472 continue;
473 }
474 break;
475 }
476 last_to = to;
477 ++n_match;
478 if (st < from) {
479 buffer_addlstring (&BufOut, argE.text + st, from - st);
480#ifdef ALG_PULL
481 st = from;
482#endif
483 }
484 /*----------------------------------------------------------------*/
485 if (argE.reptype == LUA_TSTRING) {
486 size_t iter = 0, num;
487 const char *str;
488 while (bufferZ_next (&BufRep, &iter, &num, &str)) {
489 if (str)
490 buffer_addlstring (pBuf, str, num);
491 else if (num == 0 || ALG_SUBVALID (ud,num))
492 buffer_addlstring (pBuf, argE.text + ALG_BASE(st) + ALG_SUBBEG(ud,num), ALG_SUBLEN(ud,num));
493 }
494 curr_subst = 1;
495 }
496 /*----------------------------------------------------------------*/
497 else if (argE.reptype == LUA_TTABLE) {
498 if (ALG_NSUB(ud) > 0)
499 ALG_PUSHSUB_OR_FALSE (L, ud, argE.text + ALG_BASE(st), 1);
500 else
501 lua_pushlstring (L, argE.text + from, to - from);
502 lua_gettable (L, argE.funcpos);
503 }
504 /*----------------------------------------------------------------*/
505 else if (argE.reptype == LUA_TFUNCTION) {
506 int narg;
507 lua_pushvalue (L, argE.funcpos);
508 if (ALG_NSUB(ud) > 0) {
509 push_substrings (L, ud, argE.text + ALG_BASE(st), &freelist);
510 narg = ALG_NSUB(ud);
511 }
512 else {
513 lua_pushlstring (L, argE.text + from, to - from);
514 narg = 1;
515 }
516 if (0 != lua_pcall (L, narg, 1, 0)) {
517 freelist_free (&freelist);
518 return lua_error (L); /* re-raise the error */
519 }
520 }
521 /*----------------------------------------------------------------*/
522 if (argE.reptype == LUA_TTABLE || argE.reptype == LUA_TFUNCTION) {
523 if (lua_tostring (L, -1)) {
524 buffer_addvalue (pBuf, -1);
525 curr_subst = 1;
526 }
527 else if (!lua_toboolean (L, -1))
528 buffer_addlstring (pBuf, argE.text + from, to - from);
529 else {
530 freelist_free (&freelist);
531 luaL_error (L, "invalid replacement value (a %s)", luaL_typename (L, -1));
532 }
533 if (argE.maxmatch != GSUB_CONDITIONAL)
534 lua_pop (L, 1);
535 }
536 /*----------------------------------------------------------------*/
537 if (argE.maxmatch == GSUB_CONDITIONAL) {
538 /* Call the function */
539 lua_pushvalue (L, argE.funcpos2);
540 lua_pushinteger (L, from/ALG_CHARSIZE + 1);
541 lua_pushinteger (L, to/ALG_CHARSIZE);
542 if (argE.reptype == LUA_TSTRING)
543 buffer_pushresult (&BufTemp);
544 else {
545 lua_pushvalue (L, -4);
546 lua_remove (L, -5);
547 }
548 if (0 != lua_pcall (L, 3, 2, 0)) {
549 freelist_free (&freelist);
550 lua_error (L); /* re-raise the error */
551 }
552 /* Handle the 1-st return value */
553 if (lua_isstring (L, -2)) { /* coercion is allowed here */
554 buffer_addvalue (&BufOut, -2); /* rep2 */
555 curr_subst = 1;
556 }
557 else if (lua_toboolean (L, -2))
558 buffer_addbuffer (&BufOut, &BufTemp); /* rep1 */
559 else {
560 buffer_addlstring (&BufOut, argE.text + from, to - from); /* "no" */
561 curr_subst = 0;
562 }
563 /* Handle the 2-nd return value */
564 if (lua_type (L, -1) == LUA_TNUMBER) { /* no coercion is allowed here */
565 int n = lua_tointeger (L, -1);
566 if (n < 0) /* n */
567 n = 0;
568 argE.maxmatch = n_match + n;
569 }
570 else if (lua_toboolean (L, -1)) /* "yes to all" */
571 argE.maxmatch = GSUB_UNLIMITED;
572 else
573 buffer_clear (&BufTemp);
574
575 lua_pop (L, 2);
576 if (argE.maxmatch != GSUB_CONDITIONAL)
577 pBuf = &BufOut;
578 }
579 /*----------------------------------------------------------------*/
580 n_subst += curr_subst;
581 if (st < to) {
582 st = to;
583 }
584 else if (st < (int)argE.textlen) {
585 /* advance by 1 char (not replaced) */
586 buffer_addlstring (&BufOut, argE.text + st, ALG_CHARSIZE);
587 st += ALG_CHARSIZE;
588 }
589 else break;
590 }
591 /*------------------------------------------------------------------*/
592 buffer_addlstring (&BufOut, argE.text + st, argE.textlen - st);
593 buffer_pushresult (&BufOut);
594 lua_pushinteger (L, n_match);
595 lua_pushinteger (L, n_subst);
596 freelist_free (&freelist);
597 return 3;
598}
599
600
609static int algf_count (lua_State *L) {
610 TUserdata *ud;
611 TArgComp argC;
612 TArgExec argE;
613 int n_match = 0, st = 0, last_to = -1;
614 /*------------------------------------------------------------------*/
615 checkarg_count (L, &argC, &argE);
616 if (argC.ud) {
617 ud = (TUserdata*) argC.ud;
618 lua_pushvalue (L, 2);
619 }
620 else compile_regex (L, &argC, &ud);
621 /*------------------------------------------------------------------*/
622 while (st <= (int)argE.textlen) {
623 int to, res;
624 res = gsub_exec (ud, &argE, st);
625 if (ALG_NOMATCH (res)) {
626 break;
627 }
628 else if (!ALG_ISMATCH (res)) {
629 return generate_error (L, ud, res);
630 }
631 to = ALG_BASE(st) + ALG_SUBEND(ud,0);
632 if (to == last_to) { /* discard an empty match adjacent to the previous match */
633 if (st < (int)argE.textlen) { /* advance by 1 char */
634 st += ALG_CHARSIZE;
635 continue;
636 }
637 break;
638 }
639 last_to = to;
640 ++n_match;
641#ifdef ALG_PULL
642 {
643 int from = ALG_BASE(st) + ALG_SUBBEG(ud,0);
644 if (st < from)
645 st = from;
646 }
647#endif
648 /*----------------------------------------------------------------*/
649 if (st < to) {
650 st = to;
651 }
652 else if (st < (int)argE.textlen) {
653 /* advance by 1 char (not replaced) */
654 st += ALG_CHARSIZE;
655 }
656 else break;
657 }
658 /*------------------------------------------------------------------*/
659 lua_pushinteger (L, n_match);
660 return 1;
661}
662
663
677static int finish_generic_find (lua_State *L, TUserdata *ud, TArgExec *argE,
678 int method, int res)
679{
680 if (ALG_ISMATCH (res)) {
681 if (method == METHOD_FIND)
682 ALG_PUSHOFFSETS (L, ud, ALG_BASE(argE->startoffset), 0);
683 if (ALG_NSUB(ud)) /* push captures */
684 push_substrings (L, ud, argE->text, NULL);
685 else if (method != METHOD_FIND) {
686 ALG_PUSHSUB (L, ud, argE->text, 0);
687 return 1;
688 }
689 return (method == METHOD_FIND) ? ALG_NSUB(ud) + 2 : ALG_NSUB(ud);
690 }
691 else if (ALG_NOMATCH (res))
692 return lua_pushnil (L), 1;
693 else
694 return generate_error (L, ud, res);
695}
696
697
707static int generic_find_func (lua_State *L, int method) {
708 TUserdata *ud;
709 TArgComp argC;
710 TArgExec argE;
711 int res;
712
713 checkarg_find_func (L, &argC, &argE);
714 if (argE.startoffset > (int)argE.textlen)
715 return lua_pushnil (L), 1;
716
717 if (argC.ud) {
718 ud = (TUserdata*) argC.ud;
719 lua_pushvalue (L, 2);
720 }
721 else compile_regex (L, &argC, &ud);
722 res = findmatch_exec (ud, &argE);
723 return finish_generic_find (L, ud, &argE, method, res);
724}
725
726
733static int algf_find (lua_State *L) {
734 return generic_find_func (L, METHOD_FIND);
735}
736
737
746static int algf_match (lua_State *L) {
747 return generic_find_func (L, METHOD_MATCH);
748}
749
750
759static int gmatch_iter (lua_State *L) {
760 int last_end, res;
761 TArgExec argE;
762 TUserdata *ud = (TUserdata*) lua_touserdata (L, lua_upvalueindex (1));
763 argE.text = lua_tolstring (L, lua_upvalueindex (2), &argE.textlen);
764 argE.eflags = lua_tointeger (L, lua_upvalueindex (3));
765 argE.startoffset = lua_tointeger (L, lua_upvalueindex (4));
766 last_end = lua_tointeger (L, lua_upvalueindex (5));
767
768 while (1) {
769 if (argE.startoffset > (int)argE.textlen)
770 return 0;
771 res = gmatch_exec (ud, &argE);
772 if (ALG_ISMATCH (res)) {
773 int incr = 0;
774 if (!ALG_SUBLEN(ud,0)) { /* no progress: prevent endless loop */
775 if (last_end == ALG_BASE(argE.startoffset) + ALG_SUBEND(ud,0)) {
776 argE.startoffset += ALG_CHARSIZE;
777 continue;
778 }
779 incr = ALG_CHARSIZE;
780 }
781 last_end = ALG_BASE(argE.startoffset) + ALG_SUBEND(ud,0);
782 lua_pushinteger(L, last_end + incr); /* update start offset */
783 lua_replace (L, lua_upvalueindex (4));
784 lua_pushinteger(L, last_end); /* update last end of match */
785 lua_replace (L, lua_upvalueindex (5));
786 /* push either captures or entire match */
787 if (ALG_NSUB(ud)) {
788 push_substrings (L, ud, argE.text, NULL);
789 return ALG_NSUB(ud);
790 }
791 else {
792 ALG_PUSHSUB (L, ud, argE.text, 0);
793 return 1;
794 }
795 }
796 else if (ALG_NOMATCH (res))
797 return 0;
798 else
799 return generate_error (L, ud, res);
800 }
801}
802
803
814static int split_iter (lua_State *L) {
815 int incr, last_end, newoffset, res;
816 TArgExec argE;
817 TUserdata *ud = (TUserdata*) lua_touserdata (L, lua_upvalueindex (1));
818 argE.text = lua_tolstring (L, lua_upvalueindex (2), &argE.textlen);
819 argE.eflags = lua_tointeger (L, lua_upvalueindex (3));
820 argE.startoffset = lua_tointeger (L, lua_upvalueindex (4));
821 incr = lua_tointeger (L, lua_upvalueindex (5));
822 last_end = lua_tointeger (L, lua_upvalueindex (6));
823
824 if (incr < 0)
825 return 0;
826
827 while (1) {
828 if ((newoffset = argE.startoffset + incr) > (int)argE.textlen)
829 break;
830 res = split_exec (ud, &argE, newoffset);
831 if (ALG_ISMATCH (res)) {
832 if (!ALG_SUBLEN(ud,0)) { /* no progress: prevent endless loop */
833 if (last_end == ALG_BASE(argE.startoffset) + ALG_SUBEND(ud,0)) {
834 incr += ALG_CHARSIZE;
835 continue;
836 }
837 }
838 lua_pushinteger(L, ALG_BASE(newoffset) + ALG_SUBEND(ud,0)); /* update start offset and last_end */
839 lua_pushvalue (L, -1);
840 lua_replace (L, lua_upvalueindex (4));
841 lua_replace (L, lua_upvalueindex (6));
842 lua_pushinteger (L, ALG_SUBLEN(ud,0) ? 0 : ALG_CHARSIZE); /* update incr */
843 lua_replace (L, lua_upvalueindex (5));
844 /* push text preceding the match */
845 lua_pushlstring (L, argE.text + argE.startoffset,
846 ALG_SUBBEG(ud,0) + ALG_BASE(newoffset) - argE.startoffset);
847 /* push either captures or entire match */
848 if (ALG_NSUB(ud)) {
849 push_substrings (L, ud, argE.text + ALG_BASE(newoffset), NULL);
850 return 1 + ALG_NSUB(ud);
851 }
852 else {
853 ALG_PUSHSUB (L, ud, argE.text + ALG_BASE(newoffset), 0);
854 return 2;
855 }
856 }
857 else if (ALG_NOMATCH (res))
858 break;
859 else
860 return generate_error (L, ud, res);
861 }
862 lua_pushinteger (L, -1); /* mark as last iteration */
863 lua_replace (L, lua_upvalueindex (5)); /* incr = -1 */
864 lua_pushlstring (L, argE.text+argE.startoffset, argE.textlen-argE.startoffset);
865 return 1;
866}
867
868
877static int algf_gmatch (lua_State *L)
878{
879 TArgComp argC;
880 TArgExec argE;
881 checkarg_gmatch_split (L, &argC, &argE);
882 if (argC.ud)
883 lua_pushvalue (L, 2);
884 else
885 compile_regex (L, &argC, NULL); /* 1-st upvalue: ud */
886 gmatch_pushsubject (L, &argE); /* 2-nd upvalue: s */
887 lua_pushinteger (L, argE.eflags); /* 3-rd upvalue: ef */
888 lua_pushinteger (L, 0); /* 4-th upvalue: startoffset */
889 lua_pushinteger (L, -1); /* 5-th upvalue: last end of match */
890 lua_pushcclosure (L, gmatch_iter, 5);
891 return 1;
892}
893
902static int algf_split (lua_State *L)
903{
904 TArgComp argC;
905 TArgExec argE;
906 checkarg_gmatch_split (L, &argC, &argE);
907 if (argC.ud)
908 lua_pushvalue (L, 2);
909 else
910 compile_regex (L, &argC, NULL); /* 1-st upvalue: ud */
911 gmatch_pushsubject (L, &argE); /* 2-nd upvalue: s */
912 lua_pushinteger (L, argE.eflags); /* 3-rd upvalue: ef */
913 lua_pushinteger (L, 0); /* 4-th upvalue: startoffset */
914 lua_pushinteger (L, 0); /* 5-th upvalue: incr */
915 lua_pushinteger (L, -1); /* 6-th upvalue: last_end */
916 lua_pushcclosure (L, split_iter, 6);
917 return 1;
918}
919
920
931static void push_substring_table (lua_State *L, TUserdata *ud, const char *text) {
932 int i;
933 lua_newtable (L);
934 for (i = 1; i <= ALG_NSUB(ud); i++) {
935 ALG_PUSHSUB_OR_FALSE (L, ud, text, i);
936 lua_rawseti (L, -2, i);
937 }
938}
939
940
950static void push_offset_table (lua_State *L, TUserdata *ud, int startoffset) {
951 int i, j;
952 lua_newtable (L);
953 for (i=1, j=1; i <= ALG_NSUB(ud); i++) {
954 if (ALG_SUBVALID (ud,i)) {
955 ALG_PUSHSTART (L, ud, startoffset, i);
956 lua_rawseti (L, -2, j++);
957 ALG_PUSHEND (L, ud, startoffset, i);
958 lua_rawseti (L, -2, j++);
959 }
960 else {
961 lua_pushboolean (L, 0);
962 lua_rawseti (L, -2, j++);
963 lua_pushboolean (L, 0);
964 lua_rawseti (L, -2, j++);
965 }
966 }
967}
968
969
981static int generic_find_method (lua_State *L, int method) {
982 TUserdata *ud;
983 TArgExec argE;
984 int res;
985
986 checkarg_find_method (L, &argE, &ud);
987 if (argE.startoffset > (int)argE.textlen)
988 return lua_pushnil(L), 1;
989
990 res = findmatch_exec (ud, &argE);
991 if (ALG_ISMATCH (res)) {
992 switch (method) {
993 case METHOD_EXEC:
994 ALG_PUSHOFFSETS (L, ud, ALG_BASE(argE.startoffset), 0);
995 push_offset_table (L, ud, ALG_BASE(argE.startoffset));
996 DO_NAMED_SUBPATTERNS (L, ud, argE.text);
997 return 3;
998 case METHOD_TFIND:
999 ALG_PUSHOFFSETS (L, ud, ALG_BASE(argE.startoffset), 0);
1000 push_substring_table (L, ud, argE.text);
1001 DO_NAMED_SUBPATTERNS (L, ud, argE.text);
1002 return 3;
1003 case METHOD_MATCH:
1004 case METHOD_FIND:
1005 return finish_generic_find (L, ud, &argE, method, res);
1006 }
1007 return 0;
1008 }
1009 else if (ALG_NOMATCH (res))
1010 return lua_pushnil (L), 1;
1011 else
1012 return generate_error(L, ud, res);
1013}
1014
1015
1024static int algm_find (lua_State *L) {
1025 return generic_find_method (L, METHOD_FIND);
1026}
1027
1028static int algm_match (lua_State *L) {
1029 return generic_find_method (L, METHOD_MATCH);
1030}
1031
1032static int algm_tfind (lua_State *L) {
1033 return generic_find_method (L, METHOD_TFIND);
1034}
1035
1044static int algm_exec (lua_State *L) {
1045 return generic_find_method (L, METHOD_EXEC);
1046}
1047
1060static void alg_register (lua_State *L, const luaL_Reg *r_methods,
1061 const luaL_Reg *r_functions, const char *name) {
1062 /* Create a new function environment to serve as a metatable for methods. */
1063#if LUA_VERSION_NUM == 501
1064 lua_newtable (L);
1065 lua_pushvalue (L, -1);
1066 lua_replace (L, LUA_ENVIRONINDEX);
1067 luaL_register (L, NULL, r_methods);
1068#else
1069 luaL_newmetatable(L, REX_TYPENAME);
1070 lua_pushvalue(L, -1);
1071 luaL_setfuncs (L, r_methods, 1);
1072#endif
1073 lua_pushvalue(L, -1); /* mt.__index = mt */
1074 lua_setfield(L, -2, "__index");
1075
1076 /* Register functions. */
1077 lua_createtable(L, 0, 8);
1078#if LUA_VERSION_NUM == 501
1079 luaL_register (L, NULL, r_functions);
1080#else
1081 lua_pushvalue(L, -2);
1082 luaL_setfuncs (L, r_functions, 1);
1083#endif
1084#ifdef REX_CREATEGLOBALVAR
1085 lua_pushvalue(L, -1);
1086 lua_setglobal(L, REX_LIBNAME);
1087#endif
1088 lua_pushfstring (L, REX_VERSION" (for %s)", name);
1089 lua_setfield (L, -2, "_VERSION");
1090#ifndef REX_NOEMBEDDEDTEST
1091 lua_pushcfunction (L, newmembuffer);
1092 lua_setfield (L, -2, "_newmembuffer");
1093#endif
1094}
Definition common.h:33
Definition common.h:46
Definition common.h:61
Definition common.h:69