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 */
16static void gmatch_pushsubject (lua_State *L, TArgExec *argE);
17
25static int findmatch_exec (TUserdata *ud, TArgExec *argE);
26
35static int split_exec (TUserdata *ud, TArgExec *argE, int offset);
36
45static int gsub_exec (TUserdata *ud, TArgExec *argE, int offset);
46
54static int gmatch_exec (TUserdata *ud, TArgExec *argE);
55
64static int compile_regex (lua_State *L, const TArgComp *argC, TUserdata **pud);
65
74static int generate_error (lua_State *L, const TUserdata *ud, int errcode);
75
76#if LUA_VERSION_NUM == 501
77# define ALG_ENVIRONINDEX LUA_ENVIRONINDEX
78#else
79# define ALG_ENVIRONINDEX lua_upvalueindex(1)
80#endif
81
82#ifndef ALG_CHARSIZE
83# define ALG_CHARSIZE 1
84#endif
85
86#ifndef BUFFERZ_PUTREPSTRING
87# define BUFFERZ_PUTREPSTRING bufferZ_putrepstring
88#endif
89
90#ifndef ALG_GETCARGS
91# define ALG_GETCARGS(a,b,c)
92#endif
93
94#ifndef DO_NAMED_SUBPATTERNS
95#define DO_NAMED_SUBPATTERNS(a,b,c)
96#endif
97
98#define METHOD_FIND 0
99#define METHOD_MATCH 1
100#define METHOD_EXEC 2
101#define METHOD_TFIND 3
102
103
116static int OptLimit (lua_State *L, int pos) {
117 if (lua_isnoneornil (L, pos))
118 return GSUB_UNLIMITED;
119 if (lua_isfunction (L, pos))
120 return GSUB_CONDITIONAL;
121 if (lua_isnumber (L, pos)) {
122 int a = lua_tointeger (L, pos);
123 return a < 0 ? 0 : a;
124 }
125 return luaL_typerror (L, pos, "number or function");
126}
127
128
141static int get_startoffset(lua_State *L, int stackpos, size_t len) {
142 int startoffset = (int)luaL_optinteger(L, stackpos, 1);
143 if(startoffset > 0)
144 startoffset--;
145 else if(startoffset < 0) {
146 startoffset += len/ALG_CHARSIZE;
147 if(startoffset < 0)
148 startoffset = 0;
149 }
150 return startoffset*ALG_CHARSIZE;
151}
152
153
164static TUserdata* test_ud (lua_State *L, int pos)
165{
166 TUserdata *ud;
167 if (lua_getmetatable(L, pos) &&
168 lua_rawequal(L, -1, ALG_ENVIRONINDEX) &&
169 (ud = (TUserdata *)lua_touserdata(L, pos)) != NULL) {
170 lua_pop(L, 1);
171 return ud;
172 }
173 return NULL;
174}
175
176
185static TUserdata* check_ud (lua_State *L)
186{
187 TUserdata *ud = test_ud(L, 1);
188 if (ud == NULL) luaL_typerror(L, 1, REX_TYPENAME);
189 return ud;
190}
191
192
200static void check_subject (lua_State *L, int pos, TArgExec *argE)
201{
202 int stype;
203 argE->text = lua_tolstring (L, pos, &argE->textlen);
204 stype = lua_type (L, pos);
205 if (stype != LUA_TSTRING && stype != LUA_TTABLE && stype != LUA_TUSERDATA) {
206 luaL_typerror (L, pos, "string, table or userdata");
207 } else if (argE->text == NULL) {
208 int type;
209 lua_getfield (L, pos, "topointer");
210 if (lua_type (L, -1) != LUA_TFUNCTION)
211 luaL_error (L, "subject has no topointer method");
212 lua_pushvalue (L, pos);
213 lua_call (L, 1, 1);
214 type = lua_type (L, -1);
215 if (type != LUA_TLIGHTUSERDATA)
216 luaL_error (L, "subject's topointer method returned %s (expected lightuserdata)",
217 lua_typename (L, type));
218 argE->text = (const char*) lua_touserdata (L, -1);
219 lua_pop (L, 1);
220#if LUA_VERSION_NUM == 501
221 if (luaL_callmeta (L, pos, "__len")) {
222 if (lua_type (L, -1) != LUA_TNUMBER)
223 luaL_argerror (L, pos, "subject's length is not a number");
224 argE->textlen = lua_tointeger (L, -1);
225 lua_pop (L, 1);
226 }
227 else
228 argE->textlen = lua_objlen (L, pos);
229#else
230 argE->textlen = luaL_len (L, pos);
231#endif
232 }
233}
234
246static void check_pattern (lua_State *L, int pos, TArgComp *argC)
247{
248 if (lua_isstring (L, pos)) {
249 argC->pattern = lua_tolstring (L, pos, &argC->patlen);
250 argC->ud = NULL;
251 }
252 else if ((argC->ud = test_ud (L, pos)) == NULL)
253 luaL_typerror(L, pos, "string or " REX_TYPENAME);
254}
255
264static void checkarg_new (lua_State *L, TArgComp *argC) {
265 argC->pattern = luaL_checklstring (L, 1, &argC->patlen);
266 argC->cflags = ALG_GETCFLAGS (L, 2);
267 ALG_GETCARGS (L, 3, argC);
268}
269
270
271/* function gsub (s, patt, f, [n], [cf], [ef], [larg...]) */
272
282static void checkarg_gsub (lua_State *L, TArgComp *argC, TArgExec *argE) {
283 check_subject (L, 1, argE);
284 check_pattern (L, 2, argC);
285 lua_tostring (L, 3); /* converts number (if any) to string */
286 argE->reptype = lua_type (L, 3);
287 if (argE->reptype != LUA_TSTRING && argE->reptype != LUA_TTABLE &&
288 argE->reptype != LUA_TFUNCTION) {
289 luaL_typerror (L, 3, "string, table or function");
290 }
291 argE->funcpos = 3;
292 argE->funcpos2 = 4;
293 argE->maxmatch = OptLimit (L, 4);
294 argC->cflags = ALG_GETCFLAGS (L, 5);
295 argE->eflags = (int)luaL_optinteger (L, 6, ALG_EFLAGS_DFLT);
296 ALG_GETCARGS (L, 7, argC);
297}
298
299
300/* function count (s, patt, [cf], [ef], [larg...]) */
301
312static void checkarg_count (lua_State *L, TArgComp *argC, TArgExec *argE) {
313 check_subject (L, 1, argE);
314 check_pattern (L, 2, argC);
315 argC->cflags = ALG_GETCFLAGS (L, 3);
316 argE->eflags = (int)luaL_optinteger (L, 4, ALG_EFLAGS_DFLT);
317 ALG_GETCARGS (L, 5, argC);
318}
319
320
321/* function find (s, patt, [st], [cf], [ef], [larg...]) */
322/* function match (s, patt, [st], [cf], [ef], [larg...]) */
323
333static void checkarg_find_func (lua_State *L, TArgComp *argC, TArgExec *argE) {
334 check_subject (L, 1, argE);
335 check_pattern (L, 2, argC);
336 argE->startoffset = get_startoffset (L, 3, argE->textlen);
337 argC->cflags = ALG_GETCFLAGS (L, 4);
338 argE->eflags = (int)luaL_optinteger (L, 5, ALG_EFLAGS_DFLT);
339 ALG_GETCARGS (L, 6, argC);
340}
341
342
343/* function gmatch (s, patt, [cf], [ef], [larg...]) */
344/* function split (s, patt, [cf], [ef], [larg...]) */
345
355static void checkarg_gmatch_split (lua_State *L, TArgComp *argC, TArgExec *argE) {
356 check_subject (L, 1, argE);
357 check_pattern (L, 2, argC);
358 argC->cflags = ALG_GETCFLAGS (L, 3);
359 argE->eflags = (int)luaL_optinteger (L, 4, ALG_EFLAGS_DFLT);
360 ALG_GETCARGS (L, 5, argC);
361}
362
363
364/* method r:tfind (s, [st], [ef]) */
365/* method r:exec (s, [st], [ef]) */
366/* method r:find (s, [st], [ef]) */
367/* method r:match (s, [st], [ef]) */
368
378static void checkarg_find_method (lua_State *L, TArgExec *argE, TUserdata **ud) {
379 *ud = check_ud (L);
380 check_subject (L, 2, argE);
381 argE->startoffset = get_startoffset (L, 3, argE->textlen);
382 argE->eflags = (int)luaL_optinteger (L, 4, ALG_EFLAGS_DFLT);
383}
384
385
394static int algf_new (lua_State *L) {
395 TArgComp argC;
396 checkarg_new (L, &argC);
397 return compile_regex (L, &argC, NULL);
398}
399
412static void push_substrings (lua_State *L, TUserdata *ud, const char *text,
413 TFreeList *freelist) {
414 int i;
415 if (lua_checkstack (L, ALG_NSUB(ud)) == 0) {
416 if (freelist)
417 freelist_free (freelist);
418 luaL_error (L, "cannot add %d stack slots", ALG_NSUB(ud));
419 }
420 for (i = 1; i <= ALG_NSUB(ud); i++) {
421 ALG_PUSHSUB_OR_FALSE (L, ud, text, i);
422 }
423}
424
434static int algf_gsub (lua_State *L) {
435 TUserdata *ud;
436 TArgComp argC;
437 TArgExec argE;
438 int n_match = 0, n_subst = 0, st = 0, last_to = -1;
439 TBuffer BufOut, BufRep, BufTemp, *pBuf = &BufOut;
440 TFreeList freelist;
441 /*------------------------------------------------------------------*/
442 checkarg_gsub (L, &argC, &argE);
443 if (argC.ud) {
444 ud = (TUserdata*) argC.ud;
445 lua_pushvalue (L, 2);
446 }
447 else compile_regex (L, &argC, &ud);
448 freelist_init (&freelist);
449 /*------------------------------------------------------------------*/
450 if (argE.reptype == LUA_TSTRING) {
451 buffer_init (&BufRep, 256, L, &freelist);
452 BUFFERZ_PUTREPSTRING (&BufRep, argE.funcpos, ALG_NSUB(ud));
453 }
454 /*------------------------------------------------------------------*/
455 if (argE.maxmatch == GSUB_CONDITIONAL) {
456 buffer_init (&BufTemp, 1024, L, &freelist);
457 pBuf = &BufTemp;
458 }
459 /*------------------------------------------------------------------*/
460 buffer_init (&BufOut, 1024, L, &freelist);
461 while ((argE.maxmatch < 0 || n_match < argE.maxmatch) && st <= (int)argE.textlen) {
462 int from, to, res;
463 int curr_subst = 0;
464 res = gsub_exec (ud, &argE, st);
465 if (ALG_NOMATCH (res)) {
466 break;
467 }
468 else if (!ALG_ISMATCH (res)) {
469 freelist_free (&freelist);
470 return generate_error (L, ud, res);
471 }
472 from = ALG_BASE(st) + ALG_SUBBEG(ud,0);
473 to = ALG_BASE(st) + ALG_SUBEND(ud,0);
474 if (to == last_to) { /* discard an empty match adjacent to the previous match */
475 if (st < (int)argE.textlen) { /* advance by 1 char (not replaced) */
476 buffer_addlstring (&BufOut, argE.text + st, ALG_CHARSIZE);
477 st += ALG_CHARSIZE;
478 continue;
479 }
480 break;
481 }
482 last_to = to;
483 ++n_match;
484 if (st < from) {
485 buffer_addlstring (&BufOut, argE.text + st, from - st);
486#ifdef ALG_PULL
487 st = from;
488#endif
489 }
490 /*----------------------------------------------------------------*/
491 if (argE.reptype == LUA_TSTRING) {
492 size_t iter = 0, num;
493 const char *str;
494 while (bufferZ_next (&BufRep, &iter, &num, &str)) {
495 if (str)
496 buffer_addlstring (pBuf, str, num);
497 else if (num == 0 || ALG_SUBVALID (ud,num))
498 buffer_addlstring (pBuf, argE.text + ALG_BASE(st) + ALG_SUBBEG(ud,num), ALG_SUBLEN(ud,num));
499 }
500 curr_subst = 1;
501 }
502 /*----------------------------------------------------------------*/
503 else if (argE.reptype == LUA_TTABLE) {
504 if (ALG_NSUB(ud) > 0)
505 ALG_PUSHSUB_OR_FALSE (L, ud, argE.text + ALG_BASE(st), 1);
506 else
507 lua_pushlstring (L, argE.text + from, to - from);
508 lua_gettable (L, argE.funcpos);
509 }
510 /*----------------------------------------------------------------*/
511 else if (argE.reptype == LUA_TFUNCTION) {
512 int narg;
513 lua_pushvalue (L, argE.funcpos);
514 if (ALG_NSUB(ud) > 0) {
515 push_substrings (L, ud, argE.text + ALG_BASE(st), &freelist);
516 narg = ALG_NSUB(ud);
517 }
518 else {
519 lua_pushlstring (L, argE.text + from, to - from);
520 narg = 1;
521 }
522 if (0 != lua_pcall (L, narg, 1, 0)) {
523 freelist_free (&freelist);
524 return lua_error (L); /* re-raise the error */
525 }
526 }
527 /*----------------------------------------------------------------*/
528 if (argE.reptype == LUA_TTABLE || argE.reptype == LUA_TFUNCTION) {
529 if (lua_tostring (L, -1)) {
530 buffer_addvalue (pBuf, -1);
531 curr_subst = 1;
532 }
533 else if (!lua_toboolean (L, -1))
534 buffer_addlstring (pBuf, argE.text + from, to - from);
535 else {
536 freelist_free (&freelist);
537 luaL_error (L, "invalid replacement value (a %s)", luaL_typename (L, -1));
538 }
539 if (argE.maxmatch != GSUB_CONDITIONAL)
540 lua_pop (L, 1);
541 }
542 /*----------------------------------------------------------------*/
543 if (argE.maxmatch == GSUB_CONDITIONAL) {
544 /* Call the function */
545 lua_pushvalue (L, argE.funcpos2);
546 lua_pushinteger (L, from/ALG_CHARSIZE + 1);
547 lua_pushinteger (L, to/ALG_CHARSIZE);
548 if (argE.reptype == LUA_TSTRING)
549 buffer_pushresult (&BufTemp);
550 else {
551 lua_pushvalue (L, -4);
552 lua_remove (L, -5);
553 }
554 if (0 != lua_pcall (L, 3, 2, 0)) {
555 freelist_free (&freelist);
556 lua_error (L); /* re-raise the error */
557 }
558 /* Handle the 1-st return value */
559 if (lua_isstring (L, -2)) { /* coercion is allowed here */
560 buffer_addvalue (&BufOut, -2); /* rep2 */
561 curr_subst = 1;
562 }
563 else if (lua_toboolean (L, -2))
564 buffer_addbuffer (&BufOut, &BufTemp); /* rep1 */
565 else {
566 buffer_addlstring (&BufOut, argE.text + from, to - from); /* "no" */
567 curr_subst = 0;
568 }
569 /* Handle the 2-nd return value */
570 if (lua_type (L, -1) == LUA_TNUMBER) { /* no coercion is allowed here */
571 int n = lua_tointeger (L, -1);
572 if (n < 0) /* n */
573 n = 0;
574 argE.maxmatch = n_match + n;
575 }
576 else if (lua_toboolean (L, -1)) /* "yes to all" */
577 argE.maxmatch = GSUB_UNLIMITED;
578 else
579 buffer_clear (&BufTemp);
580
581 lua_pop (L, 2);
582 if (argE.maxmatch != GSUB_CONDITIONAL)
583 pBuf = &BufOut;
584 }
585 /*----------------------------------------------------------------*/
586 n_subst += curr_subst;
587 if (st < to) {
588 st = to;
589 }
590 else if (st < (int)argE.textlen) {
591 /* advance by 1 char (not replaced) */
592 buffer_addlstring (&BufOut, argE.text + st, ALG_CHARSIZE);
593 st += ALG_CHARSIZE;
594 }
595 else break;
596 }
597 /*------------------------------------------------------------------*/
598 buffer_addlstring (&BufOut, argE.text + st, argE.textlen - st);
599 buffer_pushresult (&BufOut);
600 lua_pushinteger (L, n_match);
601 lua_pushinteger (L, n_subst);
602 freelist_free (&freelist);
603 return 3;
604}
605
606
615static int algf_count (lua_State *L) {
616 TUserdata *ud;
617 TArgComp argC;
618 TArgExec argE;
619 int n_match = 0, st = 0, last_to = -1;
620 /*------------------------------------------------------------------*/
621 checkarg_count (L, &argC, &argE);
622 if (argC.ud) {
623 ud = (TUserdata*) argC.ud;
624 lua_pushvalue (L, 2);
625 }
626 else compile_regex (L, &argC, &ud);
627 /*------------------------------------------------------------------*/
628 while (st <= (int)argE.textlen) {
629 int to, res;
630 res = gsub_exec (ud, &argE, st);
631 if (ALG_NOMATCH (res)) {
632 break;
633 }
634 else if (!ALG_ISMATCH (res)) {
635 return generate_error (L, ud, res);
636 }
637 to = ALG_BASE(st) + ALG_SUBEND(ud,0);
638 if (to == last_to) { /* discard an empty match adjacent to the previous match */
639 if (st < (int)argE.textlen) { /* advance by 1 char */
640 st += ALG_CHARSIZE;
641 continue;
642 }
643 break;
644 }
645 last_to = to;
646 ++n_match;
647#ifdef ALG_PULL
648 {
649 int from = ALG_BASE(st) + ALG_SUBBEG(ud,0);
650 if (st < from)
651 st = from;
652 }
653#endif
654 /*----------------------------------------------------------------*/
655 if (st < to) {
656 st = to;
657 }
658 else if (st < (int)argE.textlen) {
659 /* advance by 1 char (not replaced) */
660 st += ALG_CHARSIZE;
661 }
662 else break;
663 }
664 /*------------------------------------------------------------------*/
665 lua_pushinteger (L, n_match);
666 return 1;
667}
668
669
683static int finish_generic_find (lua_State *L, TUserdata *ud, TArgExec *argE,
684 int method, int res)
685{
686 if (ALG_ISMATCH (res)) {
687 if (method == METHOD_FIND)
688 ALG_PUSHOFFSETS (L, ud, ALG_BASE(argE->startoffset), 0);
689 if (ALG_NSUB(ud)) /* push captures */
690 push_substrings (L, ud, argE->text, NULL);
691 else if (method != METHOD_FIND) {
692 ALG_PUSHSUB (L, ud, argE->text, 0);
693 return 1;
694 }
695 return (method == METHOD_FIND) ? ALG_NSUB(ud) + 2 : ALG_NSUB(ud);
696 }
697 else if (ALG_NOMATCH (res))
698 return lua_pushnil (L), 1;
699 else
700 return generate_error (L, ud, res);
701}
702
703
713static int generic_find_func (lua_State *L, int method) {
714 TUserdata *ud;
715 TArgComp argC;
716 TArgExec argE;
717 int res;
718
719 checkarg_find_func (L, &argC, &argE);
720 if (argE.startoffset > (int)argE.textlen)
721 return lua_pushnil (L), 1;
722
723 if (argC.ud) {
724 ud = (TUserdata*) argC.ud;
725 lua_pushvalue (L, 2);
726 }
727 else compile_regex (L, &argC, &ud);
728 res = findmatch_exec (ud, &argE);
729 return finish_generic_find (L, ud, &argE, method, res);
730}
731
732
739static int algf_find (lua_State *L) {
740 return generic_find_func (L, METHOD_FIND);
741}
742
743
752static int algf_match (lua_State *L) {
753 return generic_find_func (L, METHOD_MATCH);
754}
755
756
765static int gmatch_iter (lua_State *L) {
766 int last_end, res;
767 TArgExec argE;
768 TUserdata *ud = (TUserdata*) lua_touserdata (L, lua_upvalueindex (1));
769 argE.text = lua_tolstring (L, lua_upvalueindex (2), &argE.textlen);
770 argE.eflags = lua_tointeger (L, lua_upvalueindex (3));
771 argE.startoffset = lua_tointeger (L, lua_upvalueindex (4));
772 last_end = lua_tointeger (L, lua_upvalueindex (5));
773
774 while (1) {
775 if (argE.startoffset > (int)argE.textlen)
776 return 0;
777 res = gmatch_exec (ud, &argE);
778 if (ALG_ISMATCH (res)) {
779 int incr = 0;
780 if (!ALG_SUBLEN(ud,0)) { /* no progress: prevent endless loop */
781 if (last_end == ALG_BASE(argE.startoffset) + ALG_SUBEND(ud,0)) {
782 argE.startoffset += ALG_CHARSIZE;
783 continue;
784 }
785 incr = ALG_CHARSIZE;
786 }
787 last_end = ALG_BASE(argE.startoffset) + ALG_SUBEND(ud,0);
788 lua_pushinteger(L, last_end + incr); /* update start offset */
789 lua_replace (L, lua_upvalueindex (4));
790 lua_pushinteger(L, last_end); /* update last end of match */
791 lua_replace (L, lua_upvalueindex (5));
792 /* push either captures or entire match */
793 if (ALG_NSUB(ud)) {
794 push_substrings (L, ud, argE.text, NULL);
795 return ALG_NSUB(ud);
796 }
797 else {
798 ALG_PUSHSUB (L, ud, argE.text, 0);
799 return 1;
800 }
801 }
802 else if (ALG_NOMATCH (res))
803 return 0;
804 else
805 return generate_error (L, ud, res);
806 }
807}
808
809
820static int split_iter (lua_State *L) {
821 int incr, last_end, newoffset, res;
822 TArgExec argE;
823 TUserdata *ud = (TUserdata*) lua_touserdata (L, lua_upvalueindex (1));
824 argE.text = lua_tolstring (L, lua_upvalueindex (2), &argE.textlen);
825 argE.eflags = lua_tointeger (L, lua_upvalueindex (3));
826 argE.startoffset = lua_tointeger (L, lua_upvalueindex (4));
827 incr = lua_tointeger (L, lua_upvalueindex (5));
828 last_end = lua_tointeger (L, lua_upvalueindex (6));
829
830 if (incr < 0)
831 return 0;
832
833 while (1) {
834 if ((newoffset = argE.startoffset + incr) > (int)argE.textlen)
835 break;
836 res = split_exec (ud, &argE, newoffset);
837 if (ALG_ISMATCH (res)) {
838 if (!ALG_SUBLEN(ud,0)) { /* no progress: prevent endless loop */
839 if (last_end == ALG_BASE(argE.startoffset) + ALG_SUBEND(ud,0)) {
840 incr += ALG_CHARSIZE;
841 continue;
842 }
843 }
844 lua_pushinteger(L, ALG_BASE(newoffset) + ALG_SUBEND(ud,0)); /* update start offset and last_end */
845 lua_pushvalue (L, -1);
846 lua_replace (L, lua_upvalueindex (4));
847 lua_replace (L, lua_upvalueindex (6));
848 lua_pushinteger (L, ALG_SUBLEN(ud,0) ? 0 : ALG_CHARSIZE); /* update incr */
849 lua_replace (L, lua_upvalueindex (5));
850 /* push text preceding the match */
851 lua_pushlstring (L, argE.text + argE.startoffset,
852 ALG_SUBBEG(ud,0) + ALG_BASE(newoffset) - argE.startoffset);
853 /* push either captures or entire match */
854 if (ALG_NSUB(ud)) {
855 push_substrings (L, ud, argE.text + ALG_BASE(newoffset), NULL);
856 return 1 + ALG_NSUB(ud);
857 }
858 else {
859 ALG_PUSHSUB (L, ud, argE.text + ALG_BASE(newoffset), 0);
860 return 2;
861 }
862 }
863 else if (ALG_NOMATCH (res))
864 break;
865 else
866 return generate_error (L, ud, res);
867 }
868 lua_pushinteger (L, -1); /* mark as last iteration */
869 lua_replace (L, lua_upvalueindex (5)); /* incr = -1 */
870 lua_pushlstring (L, argE.text+argE.startoffset, argE.textlen-argE.startoffset);
871 return 1;
872}
873
874
883static int algf_gmatch (lua_State *L)
884{
885 TArgComp argC;
886 TArgExec argE;
887 checkarg_gmatch_split (L, &argC, &argE);
888 if (argC.ud)
889 lua_pushvalue (L, 2);
890 else
891 compile_regex (L, &argC, NULL); /* 1-st upvalue: ud */
892 gmatch_pushsubject (L, &argE); /* 2-nd upvalue: s */
893 lua_pushinteger (L, argE.eflags); /* 3-rd upvalue: ef */
894 lua_pushinteger (L, 0); /* 4-th upvalue: startoffset */
895 lua_pushinteger (L, -1); /* 5-th upvalue: last end of match */
896 lua_pushcclosure (L, gmatch_iter, 5);
897 return 1;
898}
899
908static int algf_split (lua_State *L)
909{
910 TArgComp argC;
911 TArgExec argE;
912 checkarg_gmatch_split (L, &argC, &argE);
913 if (argC.ud)
914 lua_pushvalue (L, 2);
915 else
916 compile_regex (L, &argC, NULL); /* 1-st upvalue: ud */
917 gmatch_pushsubject (L, &argE); /* 2-nd upvalue: s */
918 lua_pushinteger (L, argE.eflags); /* 3-rd upvalue: ef */
919 lua_pushinteger (L, 0); /* 4-th upvalue: startoffset */
920 lua_pushinteger (L, 0); /* 5-th upvalue: incr */
921 lua_pushinteger (L, -1); /* 6-th upvalue: last_end */
922 lua_pushcclosure (L, split_iter, 6);
923 return 1;
924}
925
926
937static void push_substring_table (lua_State *L, TUserdata *ud, const char *text) {
938 int i;
939 lua_newtable (L);
940 for (i = 1; i <= ALG_NSUB(ud); i++) {
941 ALG_PUSHSUB_OR_FALSE (L, ud, text, i);
942 lua_rawseti (L, -2, i);
943 }
944}
945
946
956static void push_offset_table (lua_State *L, TUserdata *ud, int startoffset) {
957 int i, j;
958 lua_newtable (L);
959 for (i=1, j=1; i <= ALG_NSUB(ud); i++) {
960 if (ALG_SUBVALID (ud,i)) {
961 ALG_PUSHSTART (L, ud, startoffset, i);
962 lua_rawseti (L, -2, j++);
963 ALG_PUSHEND (L, ud, startoffset, i);
964 lua_rawseti (L, -2, j++);
965 }
966 else {
967 lua_pushboolean (L, 0);
968 lua_rawseti (L, -2, j++);
969 lua_pushboolean (L, 0);
970 lua_rawseti (L, -2, j++);
971 }
972 }
973}
974
975
987static int generic_find_method (lua_State *L, int method) {
988 TUserdata *ud;
989 TArgExec argE;
990 int res;
991
992 checkarg_find_method (L, &argE, &ud);
993 if (argE.startoffset > (int)argE.textlen)
994 return lua_pushnil(L), 1;
995
996 res = findmatch_exec (ud, &argE);
997 if (ALG_ISMATCH (res)) {
998 switch (method) {
999 case METHOD_EXEC:
1000 ALG_PUSHOFFSETS (L, ud, ALG_BASE(argE.startoffset), 0);
1001 push_offset_table (L, ud, ALG_BASE(argE.startoffset));
1002 DO_NAMED_SUBPATTERNS (L, ud, argE.text);
1003 return 3;
1004 case METHOD_TFIND:
1005 ALG_PUSHOFFSETS (L, ud, ALG_BASE(argE.startoffset), 0);
1006 push_substring_table (L, ud, argE.text);
1007 DO_NAMED_SUBPATTERNS (L, ud, argE.text);
1008 return 3;
1009 case METHOD_MATCH:
1010 case METHOD_FIND:
1011 return finish_generic_find (L, ud, &argE, method, res);
1012 }
1013 return 0;
1014 }
1015 else if (ALG_NOMATCH (res))
1016 return lua_pushnil (L), 1;
1017 else
1018 return generate_error(L, ud, res);
1019}
1020
1021
1030static int algm_find (lua_State *L) {
1031 return generic_find_method (L, METHOD_FIND);
1032}
1033
1042static int algm_match (lua_State *L) {
1043 return generic_find_method (L, METHOD_MATCH);
1044}
1045
1052static int algm_tfind (lua_State *L) {
1053 return generic_find_method (L, METHOD_TFIND);
1054}
1055
1064static int algm_exec (lua_State *L) {
1065 return generic_find_method (L, METHOD_EXEC);
1066}
1067
1080static void alg_register (lua_State *L, const luaL_Reg *r_methods,
1081 const luaL_Reg *r_functions, const char *name) {
1082 /* Create a new function environment to serve as a metatable for methods. */
1083#if LUA_VERSION_NUM == 501
1084 lua_newtable (L);
1085 lua_pushvalue (L, -1);
1086 lua_replace (L, LUA_ENVIRONINDEX);
1087 luaL_register (L, NULL, r_methods);
1088#else
1089 luaL_newmetatable(L, REX_TYPENAME);
1090 lua_pushvalue(L, -1);
1091 luaL_setfuncs (L, r_methods, 1);
1092#endif
1093 lua_pushvalue(L, -1); /* mt.__index = mt */
1094 lua_setfield(L, -2, "__index");
1095
1096 /* Register functions. */
1097 lua_createtable(L, 0, 8);
1098#if LUA_VERSION_NUM == 501
1099 luaL_register (L, NULL, r_functions);
1100#else
1101 lua_pushvalue(L, -2);
1102 luaL_setfuncs (L, r_functions, 1);
1103#endif
1104#ifdef REX_CREATEGLOBALVAR
1105 lua_pushvalue(L, -1);
1106 lua_setglobal(L, REX_LIBNAME);
1107#endif
1108 lua_pushfstring (L, REX_VERSION" (for %s)", name);
1109 lua_setfield (L, -2, "_VERSION");
1110#ifndef REX_NOEMBEDDEDTEST
1111 lua_pushcfunction (L, newmembuffer);
1112 lua_setfield (L, -2, "_newmembuffer");
1113#endif
1114}
Definition common.h:33
Definition common.h:46
Definition common.h:61
Definition common.h:69