Wireshark  2.9.0-477-g68ec514b
The Wireshark network protocol analyzer
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 }
Definition: lrexlib.h:79
Definition: lrexlib.h:64
Definition: lrexlib.h:51
Definition: lrexlib.h:87