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