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