|
@ -1,5 +1,5 @@ |
|
|
/*
|
|
|
/*
|
|
|
** $Id: lstrlib.c,v 1.124 2005/09/19 13:49:12 roberto Exp roberto $ |
|
|
** $Id: lstrlib.c,v 1.125 2005/10/19 13:05:11 roberto Exp roberto $ |
|
|
** Standard library for string operations and pattern-matching |
|
|
** Standard library for string operations and pattern-matching |
|
|
** See Copyright Notice in lua.h |
|
|
** See Copyright Notice in lua.h |
|
|
*/ |
|
|
*/ |
|
@ -462,28 +462,32 @@ static const char *lmemfind (const char *s1, size_t l1, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void push_onecapture (MatchState *ms, int i) { |
|
|
static void push_onecapture (MatchState *ms, int i, const char *s, |
|
|
ptrdiff_t l = ms->capture[i].len; |
|
|
const char *e) { |
|
|
if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); |
|
|
if (i >= ms->level) { |
|
|
if (l == CAP_POSITION) |
|
|
if (i == 0) /* ms->level == 0, too */ |
|
|
lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); |
|
|
lua_pushlstring(ms->L, s, e - s); /* add whole match */ |
|
|
else |
|
|
else |
|
|
lua_pushlstring(ms->L, ms->capture[i].init, l); |
|
|
luaL_error(ms->L, "invalid capture index"); |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
ptrdiff_t l = ms->capture[i].len; |
|
|
|
|
|
if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); |
|
|
|
|
|
if (l == CAP_POSITION) |
|
|
|
|
|
lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); |
|
|
|
|
|
else |
|
|
|
|
|
lua_pushlstring(ms->L, ms->capture[i].init, l); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int push_captures (MatchState *ms, const char *s, const char *e) { |
|
|
static int push_captures (MatchState *ms, const char *s, const char *e) { |
|
|
int i; |
|
|
int i; |
|
|
luaL_checkstack(ms->L, ms->level, "too many captures"); |
|
|
int nlevels = (ms->level == 0 && s) ? 1 : ms->level; |
|
|
if (ms->level == 0 && s) { /* no explicit captures? */ |
|
|
luaL_checkstack(ms->L, nlevels, "too many captures"); |
|
|
lua_pushlstring(ms->L, s, e-s); /* return whole match */ |
|
|
for (i = 0; i < nlevels; i++) |
|
|
return 1; |
|
|
push_onecapture(ms, i, s, e); |
|
|
} |
|
|
return nlevels; /* number of strings pushed */ |
|
|
else { /* return all captures */ |
|
|
|
|
|
for (i=0; i<ms->level; i++) |
|
|
|
|
|
push_onecapture(ms, i); |
|
|
|
|
|
return ms->level; /* number of strings pushed */ |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -582,42 +586,61 @@ static int gfind_nodef (lua_State *L) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void add_s (MatchState *ms, luaL_Buffer *b, |
|
|
static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, |
|
|
const char *s, const char *e) { |
|
|
const char *e) { |
|
|
lua_State *L = ms->L; |
|
|
size_t l, i; |
|
|
if (lua_isstring(L, 3)) { |
|
|
const char *news = lua_tolstring(ms->L, 3, &l); |
|
|
size_t l; |
|
|
for (i = 0; i < l; i++) { |
|
|
const char *news = lua_tolstring(L, 3, &l); |
|
|
if (news[i] != L_ESC) |
|
|
size_t i; |
|
|
luaL_addchar(b, news[i]); |
|
|
for (i=0; i<l; i++) { |
|
|
else { |
|
|
if (news[i] != L_ESC) |
|
|
i++; /* skip ESC */ |
|
|
|
|
|
if (!isdigit(uchar(news[i]))) |
|
|
luaL_addchar(b, news[i]); |
|
|
luaL_addchar(b, news[i]); |
|
|
|
|
|
else if (news[i] == '0') |
|
|
|
|
|
luaL_addlstring(b, s, e - s); |
|
|
else { |
|
|
else { |
|
|
i++; /* skip ESC */ |
|
|
push_onecapture(ms, news[i] - '1', s, e); |
|
|
if (!isdigit(uchar(news[i]))) |
|
|
luaL_addvalue(b); /* add capture to accumulated result */ |
|
|
luaL_addchar(b, news[i]); |
|
|
|
|
|
else { |
|
|
|
|
|
if (news[i] == '0') |
|
|
|
|
|
lua_pushlstring(L, s, e - s); /* add whole match */ |
|
|
|
|
|
else { |
|
|
|
|
|
int level = check_capture(ms, news[i]); |
|
|
|
|
|
push_onecapture(ms, level); |
|
|
|
|
|
} |
|
|
|
|
|
luaL_addvalue(b); /* add capture to accumulated result */ |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
else { /* is a function */ |
|
|
} |
|
|
int n; |
|
|
|
|
|
lua_pushvalue(L, 3); |
|
|
|
|
|
n = push_captures(ms, s, e); |
|
|
static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, |
|
|
lua_call(L, n, 1); |
|
|
const char *e) { |
|
|
if (lua_isstring(L, -1)) |
|
|
lua_State *L = ms->L; |
|
|
luaL_addvalue(b); /* add return to accumulated result */ |
|
|
switch (lua_type(L, 3)) { |
|
|
else |
|
|
case LUA_TNUMBER: |
|
|
lua_pop(L, 1); /* function result is not a string: pop it */ |
|
|
case LUA_TSTRING: { |
|
|
|
|
|
add_s(ms, b, s, e); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
case LUA_TFUNCTION: { |
|
|
|
|
|
int n; |
|
|
|
|
|
lua_pushvalue(L, 3); |
|
|
|
|
|
n = push_captures(ms, s, e); |
|
|
|
|
|
lua_call(L, n, 1); |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
case LUA_TTABLE: { |
|
|
|
|
|
push_onecapture(ms, 0, s, e); |
|
|
|
|
|
lua_gettable(L, 3); |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
default: { |
|
|
|
|
|
luaL_argerror(L, 3, "string/function/table expected"); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (!lua_toboolean(L, -1)) { /* nil or false? */ |
|
|
|
|
|
lua_pop(L, 1); |
|
|
|
|
|
lua_pushlstring(L, s, e - s); /* keep original text */ |
|
|
} |
|
|
} |
|
|
|
|
|
else if (!lua_isstring(L, -1)) |
|
|
|
|
|
luaL_error(L, "invalid replacement value"); |
|
|
|
|
|
luaL_addvalue(b); /* add result to accumulator */ |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -630,9 +653,6 @@ static int str_gsub (lua_State *L) { |
|
|
int n = 0; |
|
|
int n = 0; |
|
|
MatchState ms; |
|
|
MatchState ms; |
|
|
luaL_Buffer b; |
|
|
luaL_Buffer b; |
|
|
luaL_argcheck(L, |
|
|
|
|
|
lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)), |
|
|
|
|
|
3, "string or function expected"); |
|
|
|
|
|
luaL_buffinit(L, &b); |
|
|
luaL_buffinit(L, &b); |
|
|
ms.L = L; |
|
|
ms.L = L; |
|
|
ms.src_init = src; |
|
|
ms.src_init = src; |
|
@ -643,7 +663,7 @@ static int str_gsub (lua_State *L) { |
|
|
e = match(&ms, src, p); |
|
|
e = match(&ms, src, p); |
|
|
if (e) { |
|
|
if (e) { |
|
|
n++; |
|
|
n++; |
|
|
add_s(&ms, &b, src, e); |
|
|
add_value(&ms, &b, src, e); |
|
|
} |
|
|
} |
|
|
if (e && e>src) /* non empty match? */ |
|
|
if (e && e>src) /* non empty match? */ |
|
|
src = e; /* skip it */ |
|
|
src = e; /* skip it */ |
|
|