Blame lpcap.c

Packit Service 4e3d28
/*
Packit Service 4e3d28
** $Id: lpcap.c,v 1.6 2015/06/15 16:09:57 roberto Exp $
Packit Service 4e3d28
** Copyright 2007, Lua.org & PUC-Rio  (see 'lpeg.html' for license)
Packit Service 4e3d28
*/
Packit Service 4e3d28
Packit Service 4e3d28
#include "lua.h"
Packit Service 4e3d28
#include "lauxlib.h"
Packit Service 4e3d28
Packit Service 4e3d28
#include "lpcap.h"
Packit Service 4e3d28
#include "lptypes.h"
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
#define captype(cap)	((cap)->kind)
Packit Service 4e3d28
Packit Service 4e3d28
#define isclosecap(cap)	(captype(cap) == Cclose)
Packit Service 4e3d28
Packit Service 4e3d28
#define closeaddr(c)	((c)->s + (c)->siz - 1)
Packit Service 4e3d28
Packit Service 4e3d28
#define isfullcap(cap)	((cap)->siz != 0)
Packit Service 4e3d28
Packit Service 4e3d28
#define getfromktable(cs,v)	lua_rawgeti((cs)->L, ktableidx((cs)->ptop), v)
Packit Service 4e3d28
Packit Service 4e3d28
#define pushluaval(cs)		getfromktable(cs, (cs)->cap->idx)
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Put at the cache for Lua values the value indexed by 'v' in ktable
Packit Service 4e3d28
** of the running pattern (if it is not there yet); returns its index.
Packit Service 4e3d28
*/
Packit Service 4e3d28
static int updatecache (CapState *cs, int v) {
Packit Service 4e3d28
  int idx = cs->ptop + 1;  /* stack index of cache for Lua values */
Packit Service 4e3d28
  if (v != cs->valuecached) {  /* not there? */
Packit Service 4e3d28
    getfromktable(cs, v);  /* get value from 'ktable' */
Packit Service 4e3d28
    lua_replace(cs->L, idx);  /* put it at reserved stack position */
Packit Service 4e3d28
    cs->valuecached = v;  /* keep track of what is there */
Packit Service 4e3d28
  }
Packit Service 4e3d28
  return idx;
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
static int pushcapture (CapState *cs);
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Goes back in a list of captures looking for an open capture
Packit Service 4e3d28
** corresponding to a close
Packit Service 4e3d28
*/
Packit Service 4e3d28
static Capture *findopen (Capture *cap) {
Packit Service 4e3d28
  int n = 0;  /* number of closes waiting an open */
Packit Service 4e3d28
  for (;;) {
Packit Service 4e3d28
    cap--;
Packit Service 4e3d28
    if (isclosecap(cap)) n++;  /* one more open to skip */
Packit Service 4e3d28
    else if (!isfullcap(cap))
Packit Service 4e3d28
      if (n-- == 0) return cap;
Packit Service 4e3d28
  }
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Go to the next capture
Packit Service 4e3d28
*/
Packit Service 4e3d28
static void nextcap (CapState *cs) {
Packit Service 4e3d28
  Capture *cap = cs->cap;
Packit Service 4e3d28
  if (!isfullcap(cap)) {  /* not a single capture? */
Packit Service 4e3d28
    int n = 0;  /* number of opens waiting a close */
Packit Service 4e3d28
    for (;;) {  /* look for corresponding close */
Packit Service 4e3d28
      cap++;
Packit Service 4e3d28
      if (isclosecap(cap)) {
Packit Service 4e3d28
        if (n-- == 0) break;
Packit Service 4e3d28
      }
Packit Service 4e3d28
      else if (!isfullcap(cap)) n++;
Packit Service 4e3d28
    }
Packit Service 4e3d28
  }
Packit Service 4e3d28
  cs->cap = cap + 1;  /* + 1 to skip last close (or entire single capture) */
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Push on the Lua stack all values generated by nested captures inside
Packit Service 4e3d28
** the current capture. Returns number of values pushed. 'addextra'
Packit Service 4e3d28
** makes it push the entire match after all captured values. The
Packit Service 4e3d28
** entire match is pushed also if there are no other nested values,
Packit Service 4e3d28
** so the function never returns zero.
Packit Service 4e3d28
*/
Packit Service 4e3d28
static int pushnestedvalues (CapState *cs, int addextra) {
Packit Service 4e3d28
  Capture *co = cs->cap;
Packit Service 4e3d28
  if (isfullcap(cs->cap++)) {  /* no nested captures? */
Packit Service 4e3d28
    lua_pushlstring(cs->L, co->s, co->siz - 1);  /* push whole match */
Packit Service 4e3d28
    return 1;  /* that is it */
Packit Service 4e3d28
  }
Packit Service 4e3d28
  else {
Packit Service 4e3d28
    int n = 0;
Packit Service 4e3d28
    while (!isclosecap(cs->cap))  /* repeat for all nested patterns */
Packit Service 4e3d28
      n += pushcapture(cs);
Packit Service 4e3d28
    if (addextra || n == 0) {  /* need extra? */
Packit Service 4e3d28
      lua_pushlstring(cs->L, co->s, cs->cap->s - co->s);  /* push whole match */
Packit Service 4e3d28
      n++;
Packit Service 4e3d28
    }
Packit Service 4e3d28
    cs->cap++;  /* skip close entry */
Packit Service 4e3d28
    return n;
Packit Service 4e3d28
  }
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Push only the first value generated by nested captures
Packit Service 4e3d28
*/
Packit Service 4e3d28
static void pushonenestedvalue (CapState *cs) {
Packit Service 4e3d28
  int n = pushnestedvalues(cs, 0);
Packit Service 4e3d28
  if (n > 1)
Packit Service 4e3d28
    lua_pop(cs->L, n - 1);  /* pop extra values */
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Try to find a named group capture with the name given at the top of
Packit Service 4e3d28
** the stack; goes backward from 'cap'.
Packit Service 4e3d28
*/
Packit Service 4e3d28
static Capture *findback (CapState *cs, Capture *cap) {
Packit Service 4e3d28
  lua_State *L = cs->L;
Packit Service 4e3d28
  while (cap-- > cs->ocap) {  /* repeat until end of list */
Packit Service 4e3d28
    if (isclosecap(cap))
Packit Service 4e3d28
      cap = findopen(cap);  /* skip nested captures */
Packit Service 4e3d28
    else if (!isfullcap(cap))
Packit Service 4e3d28
      continue; /* opening an enclosing capture: skip and get previous */
Packit Service 4e3d28
    if (captype(cap) == Cgroup) {
Packit Service 4e3d28
      getfromktable(cs, cap->idx);  /* get group name */
Packit Service 4e3d28
      if (lp_equal(L, -2, -1)) {  /* right group? */
Packit Service 4e3d28
        lua_pop(L, 2);  /* remove reference name and group name */
Packit Service 4e3d28
        return cap;
Packit Service 4e3d28
      }
Packit Service 4e3d28
      else lua_pop(L, 1);  /* remove group name */
Packit Service 4e3d28
    }
Packit Service 4e3d28
  }
Packit Service 4e3d28
  luaL_error(L, "back reference '%s' not found", lua_tostring(L, -1));
Packit Service 4e3d28
  return NULL;  /* to avoid warnings */
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Back-reference capture. Return number of values pushed.
Packit Service 4e3d28
*/
Packit Service 4e3d28
static int backrefcap (CapState *cs) {
Packit Service 4e3d28
  int n;
Packit Service 4e3d28
  Capture *curr = cs->cap;
Packit Service 4e3d28
  pushluaval(cs);  /* reference name */
Packit Service 4e3d28
  cs->cap = findback(cs, curr);  /* find corresponding group */
Packit Service 4e3d28
  n = pushnestedvalues(cs, 0);  /* push group's values */
Packit Service 4e3d28
  cs->cap = curr + 1;
Packit Service 4e3d28
  return n;
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Table capture: creates a new table and populates it with nested
Packit Service 4e3d28
** captures.
Packit Service 4e3d28
*/
Packit Service 4e3d28
static int tablecap (CapState *cs) {
Packit Service 4e3d28
  lua_State *L = cs->L;
Packit Service 4e3d28
  int n = 0;
Packit Service 4e3d28
  lua_newtable(L);
Packit Service 4e3d28
  if (isfullcap(cs->cap++))
Packit Service 4e3d28
    return 1;  /* table is empty */
Packit Service 4e3d28
  while (!isclosecap(cs->cap)) {
Packit Service 4e3d28
    if (captype(cs->cap) == Cgroup && cs->cap->idx != 0) {  /* named group? */
Packit Service 4e3d28
      pushluaval(cs);  /* push group name */
Packit Service 4e3d28
      pushonenestedvalue(cs);
Packit Service 4e3d28
      lua_settable(L, -3);
Packit Service 4e3d28
    }
Packit Service 4e3d28
    else {  /* not a named group */
Packit Service 4e3d28
      int i;
Packit Service 4e3d28
      int k = pushcapture(cs);
Packit Service 4e3d28
      for (i = k; i > 0; i--)  /* store all values into table */
Packit Service 4e3d28
        lua_rawseti(L, -(i + 1), n + i);
Packit Service 4e3d28
      n += k;
Packit Service 4e3d28
    }
Packit Service 4e3d28
  }
Packit Service 4e3d28
  cs->cap++;  /* skip close entry */
Packit Service 4e3d28
  return 1;  /* number of values pushed (only the table) */
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Table-query capture
Packit Service 4e3d28
*/
Packit Service 4e3d28
static int querycap (CapState *cs) {
Packit Service 4e3d28
  int idx = cs->cap->idx;
Packit Service 4e3d28
  pushonenestedvalue(cs);  /* get nested capture */
Packit Service 4e3d28
  lua_gettable(cs->L, updatecache(cs, idx));  /* query cap. value at table */
Packit Service 4e3d28
  if (!lua_isnil(cs->L, -1))
Packit Service 4e3d28
    return 1;
Packit Service 4e3d28
  else {  /* no value */
Packit Service 4e3d28
    lua_pop(cs->L, 1);  /* remove nil */
Packit Service 4e3d28
    return 0;
Packit Service 4e3d28
  }
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Fold capture
Packit Service 4e3d28
*/
Packit Service 4e3d28
static int foldcap (CapState *cs) {
Packit Service 4e3d28
  int n;
Packit Service 4e3d28
  lua_State *L = cs->L;
Packit Service 4e3d28
  int idx = cs->cap->idx;
Packit Service 4e3d28
  if (isfullcap(cs->cap++) ||  /* no nested captures? */
Packit Service 4e3d28
      isclosecap(cs->cap) ||  /* no nested captures (large subject)? */
Packit Service 4e3d28
      (n = pushcapture(cs)) == 0)  /* nested captures with no values? */
Packit Service 4e3d28
    return luaL_error(L, "no initial value for fold capture");
Packit Service 4e3d28
  if (n > 1)
Packit Service 4e3d28
    lua_pop(L, n - 1);  /* leave only one result for accumulator */
Packit Service 4e3d28
  while (!isclosecap(cs->cap)) {
Packit Service 4e3d28
    lua_pushvalue(L, updatecache(cs, idx));  /* get folding function */
Packit Service 4e3d28
    lua_insert(L, -2);  /* put it before accumulator */
Packit Service 4e3d28
    n = pushcapture(cs);  /* get next capture's values */
Packit Service 4e3d28
    lua_call(L, n + 1, 1);  /* call folding function */
Packit Service 4e3d28
  }
Packit Service 4e3d28
  cs->cap++;  /* skip close entry */
Packit Service 4e3d28
  return 1;  /* only accumulator left on the stack */
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Function capture
Packit Service 4e3d28
*/
Packit Service 4e3d28
static int functioncap (CapState *cs) {
Packit Service 4e3d28
  int n;
Packit Service 4e3d28
  int top = lua_gettop(cs->L);
Packit Service 4e3d28
  pushluaval(cs);  /* push function */
Packit Service 4e3d28
  n = pushnestedvalues(cs, 0);  /* push nested captures */
Packit Service 4e3d28
  lua_call(cs->L, n, LUA_MULTRET);  /* call function */
Packit Service 4e3d28
  return lua_gettop(cs->L) - top;  /* return function's results */
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Select capture
Packit Service 4e3d28
*/
Packit Service 4e3d28
static int numcap (CapState *cs) {
Packit Service 4e3d28
  int idx = cs->cap->idx;  /* value to select */
Packit Service 4e3d28
  if (idx == 0) {  /* no values? */
Packit Service 4e3d28
    nextcap(cs);  /* skip entire capture */
Packit Service 4e3d28
    return 0;  /* no value produced */
Packit Service 4e3d28
  }
Packit Service 4e3d28
  else {
Packit Service 4e3d28
    int n = pushnestedvalues(cs, 0);
Packit Service 4e3d28
    if (n < idx)  /* invalid index? */
Packit Service 4e3d28
      return luaL_error(cs->L, "no capture '%d'", idx);
Packit Service 4e3d28
    else {
Packit Service 4e3d28
      lua_pushvalue(cs->L, -(n - idx + 1));  /* get selected capture */
Packit Service 4e3d28
      lua_replace(cs->L, -(n + 1));  /* put it in place of 1st capture */
Packit Service 4e3d28
      lua_pop(cs->L, n - 1);  /* remove other captures */
Packit Service 4e3d28
      return 1;
Packit Service 4e3d28
    }
Packit Service 4e3d28
  }
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Return the stack index of the first runtime capture in the given
Packit Service 4e3d28
** list of captures (or zero if no runtime captures)
Packit Service 4e3d28
*/
Packit Service 4e3d28
int finddyncap (Capture *cap, Capture *last) {
Packit Service 4e3d28
  for (; cap < last; cap++) {
Packit Service 4e3d28
    if (cap->kind == Cruntime)
Packit Service 4e3d28
      return cap->idx;  /* stack position of first capture */
Packit Service 4e3d28
  }
Packit Service 4e3d28
  return 0;  /* no dynamic captures in this segment */
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Calls a runtime capture. Returns number of captures removed by
Packit Service 4e3d28
** the call, including the initial Cgroup. (Captures to be added are
Packit Service 4e3d28
** on the Lua stack.)
Packit Service 4e3d28
*/
Packit Service 4e3d28
int runtimecap (CapState *cs, Capture *close, const char *s, int *rem) {
Packit Service 4e3d28
  int n, id;
Packit Service 4e3d28
  lua_State *L = cs->L;
Packit Service 4e3d28
  int otop = lua_gettop(L);
Packit Service 4e3d28
  Capture *open = findopen(close);
Packit Service 4e3d28
  assert(captype(open) == Cgroup);
Packit Service 4e3d28
  id = finddyncap(open, close);  /* get first dynamic capture argument */
Packit Service 4e3d28
  close->kind = Cclose;  /* closes the group */
Packit Service 4e3d28
  close->s = s;
Packit Service 4e3d28
  cs->cap = open; cs->valuecached = 0;  /* prepare capture state */
Packit Service 4e3d28
  luaL_checkstack(L, 4, "too many runtime captures");
Packit Service 4e3d28
  pushluaval(cs);  /* push function to be called */
Packit Service 4e3d28
  lua_pushvalue(L, SUBJIDX);  /* push original subject */
Packit Service 4e3d28
  lua_pushinteger(L, s - cs->s + 1);  /* push current position */
Packit Service 4e3d28
  n = pushnestedvalues(cs, 0);  /* push nested captures */
Packit Service 4e3d28
  lua_call(L, n + 2, LUA_MULTRET);  /* call dynamic function */
Packit Service 4e3d28
  if (id > 0) {  /* are there old dynamic captures to be removed? */
Packit Service 4e3d28
    int i;
Packit Service 4e3d28
    for (i = id; i <= otop; i++)
Packit Service 4e3d28
      lua_remove(L, id);  /* remove old dynamic captures */
Packit Service 4e3d28
    *rem = otop - id + 1;  /* total number of dynamic captures removed */
Packit Service 4e3d28
  }
Packit Service 4e3d28
  else
Packit Service 4e3d28
    *rem = 0;  /* no dynamic captures removed */
Packit Service 4e3d28
  return close - open;  /* number of captures of all kinds removed */
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Auxiliary structure for substitution and string captures: keep
Packit Service 4e3d28
** information about nested captures for future use, avoiding to push
Packit Service 4e3d28
** string results into Lua
Packit Service 4e3d28
*/
Packit Service 4e3d28
typedef struct StrAux {
Packit Service 4e3d28
  int isstring;  /* whether capture is a string */
Packit Service 4e3d28
  union {
Packit Service 4e3d28
    Capture *cp;  /* if not a string, respective capture */
Packit Service 4e3d28
    struct {  /* if it is a string... */
Packit Service 4e3d28
      const char *s;  /* ... starts here */
Packit Service 4e3d28
      const char *e;  /* ... ends here */
Packit Service 4e3d28
    } s;
Packit Service 4e3d28
  } u;
Packit Service 4e3d28
} StrAux;
Packit Service 4e3d28
Packit Service 4e3d28
#define MAXSTRCAPS	10
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Collect values from current capture into array 'cps'. Current
Packit Service 4e3d28
** capture must be Cstring (first call) or Csimple (recursive calls).
Packit Service 4e3d28
** (In first call, fills %0 with whole match for Cstring.)
Packit Service 4e3d28
** Returns number of elements in the array that were filled.
Packit Service 4e3d28
*/
Packit Service 4e3d28
static int getstrcaps (CapState *cs, StrAux *cps, int n) {
Packit Service 4e3d28
  int k = n++;
Packit Service 4e3d28
  cps[k].isstring = 1;  /* get string value */
Packit Service 4e3d28
  cps[k].u.s.s = cs->cap->s;  /* starts here */
Packit Service 4e3d28
  if (!isfullcap(cs->cap++)) {  /* nested captures? */
Packit Service 4e3d28
    while (!isclosecap(cs->cap)) {  /* traverse them */
Packit Service 4e3d28
      if (n >= MAXSTRCAPS)  /* too many captures? */
Packit Service 4e3d28
        nextcap(cs);  /* skip extra captures (will not need them) */
Packit Service 4e3d28
      else if (captype(cs->cap) == Csimple)  /* string? */
Packit Service 4e3d28
        n = getstrcaps(cs, cps, n);  /* put info. into array */
Packit Service 4e3d28
      else {
Packit Service 4e3d28
        cps[n].isstring = 0;  /* not a string */
Packit Service 4e3d28
        cps[n].u.cp = cs->cap;  /* keep original capture */
Packit Service 4e3d28
        nextcap(cs);
Packit Service 4e3d28
        n++;
Packit Service 4e3d28
      }
Packit Service 4e3d28
    }
Packit Service 4e3d28
    cs->cap++;  /* skip close */
Packit Service 4e3d28
  }
Packit Service 4e3d28
  cps[k].u.s.e = closeaddr(cs->cap - 1);  /* ends here */
Packit Service 4e3d28
  return n;
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** add next capture value (which should be a string) to buffer 'b'
Packit Service 4e3d28
*/
Packit Service 4e3d28
static int addonestring (luaL_Buffer *b, CapState *cs, const char *what);
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** String capture: add result to buffer 'b' (instead of pushing
Packit Service 4e3d28
** it into the stack)
Packit Service 4e3d28
*/
Packit Service 4e3d28
static void stringcap (luaL_Buffer *b, CapState *cs) {
Packit Service 4e3d28
  StrAux cps[MAXSTRCAPS];
Packit Service 4e3d28
  int n;
Packit Service 4e3d28
  size_t len, i;
Packit Service 4e3d28
  const char *fmt;  /* format string */
Packit Service 4e3d28
  fmt = lua_tolstring(cs->L, updatecache(cs, cs->cap->idx), &len;;
Packit Service 4e3d28
  n = getstrcaps(cs, cps, 0) - 1;  /* collect nested captures */
Packit Service 4e3d28
  for (i = 0; i < len; i++) {  /* traverse them */
Packit Service 4e3d28
    if (fmt[i] != '%')  /* not an escape? */
Packit Service 4e3d28
      luaL_addchar(b, fmt[i]);  /* add it to buffer */
Packit Service 4e3d28
    else if (fmt[++i] < '0' || fmt[i] > '9')  /* not followed by a digit? */
Packit Service 4e3d28
      luaL_addchar(b, fmt[i]);  /* add to buffer */
Packit Service 4e3d28
    else {
Packit Service 4e3d28
      int l = fmt[i] - '0';  /* capture index */
Packit Service 4e3d28
      if (l > n)
Packit Service 4e3d28
        luaL_error(cs->L, "invalid capture index (%d)", l);
Packit Service 4e3d28
      else if (cps[l].isstring)
Packit Service 4e3d28
        luaL_addlstring(b, cps[l].u.s.s, cps[l].u.s.e - cps[l].u.s.s);
Packit Service 4e3d28
      else {
Packit Service 4e3d28
        Capture *curr = cs->cap;
Packit Service 4e3d28
        cs->cap = cps[l].u.cp;  /* go back to evaluate that nested capture */
Packit Service 4e3d28
        if (!addonestring(b, cs, "capture"))
Packit Service 4e3d28
          luaL_error(cs->L, "no values in capture index %d", l);
Packit Service 4e3d28
        cs->cap = curr;  /* continue from where it stopped */
Packit Service 4e3d28
      }
Packit Service 4e3d28
    }
Packit Service 4e3d28
  }
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Substitution capture: add result to buffer 'b'
Packit Service 4e3d28
*/
Packit Service 4e3d28
static void substcap (luaL_Buffer *b, CapState *cs) {
Packit Service 4e3d28
  const char *curr = cs->cap->s;
Packit Service 4e3d28
  if (isfullcap(cs->cap))  /* no nested captures? */
Packit Service 4e3d28
    luaL_addlstring(b, curr, cs->cap->siz - 1);  /* keep original text */
Packit Service 4e3d28
  else {
Packit Service 4e3d28
    cs->cap++;  /* skip open entry */
Packit Service 4e3d28
    while (!isclosecap(cs->cap)) {  /* traverse nested captures */
Packit Service 4e3d28
      const char *next = cs->cap->s;
Packit Service 4e3d28
      luaL_addlstring(b, curr, next - curr);  /* add text up to capture */
Packit Service 4e3d28
      if (addonestring(b, cs, "replacement"))
Packit Service 4e3d28
        curr = closeaddr(cs->cap - 1);  /* continue after match */
Packit Service 4e3d28
      else  /* no capture value */
Packit Service 4e3d28
        curr = next;  /* keep original text in final result */
Packit Service 4e3d28
    }
Packit Service 4e3d28
    luaL_addlstring(b, curr, cs->cap->s - curr);  /* add last piece of text */
Packit Service 4e3d28
  }
Packit Service 4e3d28
  cs->cap++;  /* go to next capture */
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Evaluates a capture and adds its first value to buffer 'b'; returns
Packit Service 4e3d28
** whether there was a value
Packit Service 4e3d28
*/
Packit Service 4e3d28
static int addonestring (luaL_Buffer *b, CapState *cs, const char *what) {
Packit Service 4e3d28
  switch (captype(cs->cap)) {
Packit Service 4e3d28
    case Cstring:
Packit Service 4e3d28
      stringcap(b, cs);  /* add capture directly to buffer */
Packit Service 4e3d28
      return 1;
Packit Service 4e3d28
    case Csubst:
Packit Service 4e3d28
      substcap(b, cs);  /* add capture directly to buffer */
Packit Service 4e3d28
      return 1;
Packit Service 4e3d28
    default: {
Packit Service 4e3d28
      lua_State *L = cs->L;
Packit Service 4e3d28
      int n = pushcapture(cs);
Packit Service 4e3d28
      if (n > 0) {
Packit Service 4e3d28
        if (n > 1) lua_pop(L, n - 1);  /* only one result */
Packit Service 4e3d28
        if (!lua_isstring(L, -1))
Packit Service 4e3d28
          luaL_error(L, "invalid %s value (a %s)", what, luaL_typename(L, -1));
Packit Service 4e3d28
        luaL_addvalue(b);
Packit Service 4e3d28
      }
Packit Service 4e3d28
      return n;
Packit Service 4e3d28
    }
Packit Service 4e3d28
  }
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Push all values of the current capture into the stack; returns
Packit Service 4e3d28
** number of values pushed
Packit Service 4e3d28
*/
Packit Service 4e3d28
static int pushcapture (CapState *cs) {
Packit Service 4e3d28
  lua_State *L = cs->L;
Packit Service 4e3d28
  luaL_checkstack(L, 4, "too many captures");
Packit Service 4e3d28
  switch (captype(cs->cap)) {
Packit Service 4e3d28
    case Cposition: {
Packit Service 4e3d28
      lua_pushinteger(L, cs->cap->s - cs->s + 1);
Packit Service 4e3d28
      cs->cap++;
Packit Service 4e3d28
      return 1;
Packit Service 4e3d28
    }
Packit Service 4e3d28
    case Cconst: {
Packit Service 4e3d28
      pushluaval(cs);
Packit Service 4e3d28
      cs->cap++;
Packit Service 4e3d28
      return 1;
Packit Service 4e3d28
    }
Packit Service 4e3d28
    case Carg: {
Packit Service 4e3d28
      int arg = (cs->cap++)->idx;
Packit Service 4e3d28
      if (arg + FIXEDARGS > cs->ptop)
Packit Service 4e3d28
        return luaL_error(L, "reference to absent extra argument #%d", arg);
Packit Service 4e3d28
      lua_pushvalue(L, arg + FIXEDARGS);
Packit Service 4e3d28
      return 1;
Packit Service 4e3d28
    }
Packit Service 4e3d28
    case Csimple: {
Packit Service 4e3d28
      int k = pushnestedvalues(cs, 1);
Packit Service 4e3d28
      lua_insert(L, -k);  /* make whole match be first result */
Packit Service 4e3d28
      return k;
Packit Service 4e3d28
    }
Packit Service 4e3d28
    case Cruntime: {
Packit Service 4e3d28
      lua_pushvalue(L, (cs->cap++)->idx);  /* value is in the stack */
Packit Service 4e3d28
      return 1;
Packit Service 4e3d28
    }
Packit Service 4e3d28
    case Cstring: {
Packit Service 4e3d28
      luaL_Buffer b;
Packit Service 4e3d28
      luaL_buffinit(L, &b);
Packit Service 4e3d28
      stringcap(&b, cs);
Packit Service 4e3d28
      luaL_pushresult(&b);
Packit Service 4e3d28
      return 1;
Packit Service 4e3d28
    }
Packit Service 4e3d28
    case Csubst: {
Packit Service 4e3d28
      luaL_Buffer b;
Packit Service 4e3d28
      luaL_buffinit(L, &b);
Packit Service 4e3d28
      substcap(&b, cs);
Packit Service 4e3d28
      luaL_pushresult(&b);
Packit Service 4e3d28
      return 1;
Packit Service 4e3d28
    }
Packit Service 4e3d28
    case Cgroup: {
Packit Service 4e3d28
      if (cs->cap->idx == 0)  /* anonymous group? */
Packit Service 4e3d28
        return pushnestedvalues(cs, 0);  /* add all nested values */
Packit Service 4e3d28
      else {  /* named group: add no values */
Packit Service 4e3d28
        nextcap(cs);  /* skip capture */
Packit Service 4e3d28
        return 0;
Packit Service 4e3d28
      }
Packit Service 4e3d28
    }
Packit Service 4e3d28
    case Cbackref: return backrefcap(cs);
Packit Service 4e3d28
    case Ctable: return tablecap(cs);
Packit Service 4e3d28
    case Cfunction: return functioncap(cs);
Packit Service 4e3d28
    case Cnum: return numcap(cs);
Packit Service 4e3d28
    case Cquery: return querycap(cs);
Packit Service 4e3d28
    case Cfold: return foldcap(cs);
Packit Service 4e3d28
    default: assert(0); return 0;
Packit Service 4e3d28
  }
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28
Packit Service 4e3d28
/*
Packit Service 4e3d28
** Prepare a CapState structure and traverse the entire list of
Packit Service 4e3d28
** captures in the stack pushing its results. 's' is the subject
Packit Service 4e3d28
** string, 'r' is the final position of the match, and 'ptop' 
Packit Service 4e3d28
** the index in the stack where some useful values were pushed.
Packit Service 4e3d28
** Returns the number of results pushed. (If the list produces no
Packit Service 4e3d28
** results, push the final position of the match.)
Packit Service 4e3d28
*/
Packit Service 4e3d28
int getcaptures (lua_State *L, const char *s, const char *r, int ptop) {
Packit Service 4e3d28
  Capture *capture = (Capture *)lua_touserdata(L, caplistidx(ptop));
Packit Service 4e3d28
  int n = 0;
Packit Service 4e3d28
  if (!isclosecap(capture)) {  /* is there any capture? */
Packit Service 4e3d28
    CapState cs;
Packit Service 4e3d28
    cs.ocap = cs.cap = capture; cs.L = L;
Packit Service 4e3d28
    cs.s = s; cs.valuecached = 0; cs.ptop = ptop;
Packit Service 4e3d28
    do {  /* collect their values */
Packit Service 4e3d28
      n += pushcapture(&cs);
Packit Service 4e3d28
    } while (!isclosecap(cs.cap));
Packit Service 4e3d28
  }
Packit Service 4e3d28
  if (n == 0) {  /* no capture values? */
Packit Service 4e3d28
    lua_pushinteger(L, r - s + 1);  /* return only end position */
Packit Service 4e3d28
    n = 1;
Packit Service 4e3d28
  }
Packit Service 4e3d28
  return n;
Packit Service 4e3d28
}
Packit Service 4e3d28
Packit Service 4e3d28