Wireshark 2.9.0-477-g68ec514b The Wireshark network protocol analyzer

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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