aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2005-10-23 15:46:30 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2005-10-23 15:46:30 -0200
commit62367dda449d2eb3c28b686664b920808ff0f334 (patch)
treea58a271218d8106240bcb25519fc522e0b6e3fac
parent056b6a8ef480ab72a5705f2e77a3e95f7d8b2218 (diff)
downloadlua-62367dda449d2eb3c28b686664b920808ff0f334.tar.gz
lua-62367dda449d2eb3c28b686664b920808ff0f334.tar.bz2
lua-62367dda449d2eb3c28b686664b920808ff0f334.zip
string.gsub accepts a table as the replacement value
-rw-r--r--lstrlib.c124
1 files changed, 72 insertions, 52 deletions
diff --git a/lstrlib.c b/lstrlib.c
index de01678b..3a525a73 100644
--- a/lstrlib.c
+++ b/lstrlib.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstrlib.c,v 1.124 2005/09/19 13:49:12 roberto Exp roberto $ 2** $Id: lstrlib.c,v 1.125 2005/10/19 13:05:11 roberto Exp roberto $
3** Standard library for string operations and pattern-matching 3** Standard library for string operations and pattern-matching
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -462,28 +462,32 @@ static const char *lmemfind (const char *s1, size_t l1,
462} 462}
463 463
464 464
465static void push_onecapture (MatchState *ms, int i) { 465static void push_onecapture (MatchState *ms, int i, const char *s,
466 ptrdiff_t l = ms->capture[i].len; 466 const char *e) {
467 if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); 467 if (i >= ms->level) {
468 if (l == CAP_POSITION) 468 if (i == 0) /* ms->level == 0, too */
469 lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); 469 lua_pushlstring(ms->L, s, e - s); /* add whole match */
470 else 470 else
471 lua_pushlstring(ms->L, ms->capture[i].init, l); 471 luaL_error(ms->L, "invalid capture index");
472 }
473 else {
474 ptrdiff_t l = ms->capture[i].len;
475 if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
476 if (l == CAP_POSITION)
477 lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
478 else
479 lua_pushlstring(ms->L, ms->capture[i].init, l);
480 }
472} 481}
473 482
474 483
475static int push_captures (MatchState *ms, const char *s, const char *e) { 484static int push_captures (MatchState *ms, const char *s, const char *e) {
476 int i; 485 int i;
477 luaL_checkstack(ms->L, ms->level, "too many captures"); 486 int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
478 if (ms->level == 0 && s) { /* no explicit captures? */ 487 luaL_checkstack(ms->L, nlevels, "too many captures");
479 lua_pushlstring(ms->L, s, e-s); /* return whole match */ 488 for (i = 0; i < nlevels; i++)
480 return 1; 489 push_onecapture(ms, i, s, e);
481 } 490 return nlevels; /* number of strings pushed */
482 else { /* return all captures */
483 for (i=0; i<ms->level; i++)
484 push_onecapture(ms, i);
485 return ms->level; /* number of strings pushed */
486 }
487} 491}
488 492
489 493
@@ -582,42 +586,61 @@ static int gfind_nodef (lua_State *L) {
582} 586}
583 587
584 588
585static void add_s (MatchState *ms, luaL_Buffer *b, 589static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
586 const char *s, const char *e) { 590 const char *e) {
587 lua_State *L = ms->L; 591 size_t l, i;
588 if (lua_isstring(L, 3)) { 592 const char *news = lua_tolstring(ms->L, 3, &l);
589 size_t l; 593 for (i = 0; i < l; i++) {
590 const char *news = lua_tolstring(L, 3, &l); 594 if (news[i] != L_ESC)
591 size_t i; 595 luaL_addchar(b, news[i]);
592 for (i=0; i<l; i++) { 596 else {
593 if (news[i] != L_ESC) 597 i++; /* skip ESC */
598 if (!isdigit(uchar(news[i])))
594 luaL_addchar(b, news[i]); 599 luaL_addchar(b, news[i]);
600 else if (news[i] == '0')
601 luaL_addlstring(b, s, e - s);
595 else { 602 else {
596 i++; /* skip ESC */ 603 push_onecapture(ms, news[i] - '1', s, e);
597 if (!isdigit(uchar(news[i]))) 604 luaL_addvalue(b); /* add capture to accumulated result */
598 luaL_addchar(b, news[i]);
599 else {
600 if (news[i] == '0')
601 lua_pushlstring(L, s, e - s); /* add whole match */
602 else {
603 int level = check_capture(ms, news[i]);
604 push_onecapture(ms, level);
605 }
606 luaL_addvalue(b); /* add capture to accumulated result */
607 }
608 } 605 }
609 } 606 }
610 } 607 }
611 else { /* is a function */ 608}
612 int n; 609
613 lua_pushvalue(L, 3); 610
614 n = push_captures(ms, s, e); 611static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
615 lua_call(L, n, 1); 612 const char *e) {
616 if (lua_isstring(L, -1)) 613 lua_State *L = ms->L;
617 luaL_addvalue(b); /* add return to accumulated result */ 614 switch (lua_type(L, 3)) {
618 else 615 case LUA_TNUMBER:
619 lua_pop(L, 1); /* function result is not a string: pop it */ 616 case LUA_TSTRING: {
617 add_s(ms, b, s, e);
618 return;
619 }
620 case LUA_TFUNCTION: {
621 int n;
622 lua_pushvalue(L, 3);
623 n = push_captures(ms, s, e);
624 lua_call(L, n, 1);
625 break;
626 }
627 case LUA_TTABLE: {
628 push_onecapture(ms, 0, s, e);
629 lua_gettable(L, 3);
630 break;
631 }
632 default: {
633 luaL_argerror(L, 3, "string/function/table expected");
634 return;
635 }
636 }
637 if (!lua_toboolean(L, -1)) { /* nil or false? */
638 lua_pop(L, 1);
639 lua_pushlstring(L, s, e - s); /* keep original text */
620 } 640 }
641 else if (!lua_isstring(L, -1))
642 luaL_error(L, "invalid replacement value");
643 luaL_addvalue(b); /* add result to accumulator */
621} 644}
622 645
623 646
@@ -630,9 +653,6 @@ static int str_gsub (lua_State *L) {
630 int n = 0; 653 int n = 0;
631 MatchState ms; 654 MatchState ms;
632 luaL_Buffer b; 655 luaL_Buffer b;
633 luaL_argcheck(L,
634 lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)),
635 3, "string or function expected");
636 luaL_buffinit(L, &b); 656 luaL_buffinit(L, &b);
637 ms.L = L; 657 ms.L = L;
638 ms.src_init = src; 658 ms.src_init = src;
@@ -643,7 +663,7 @@ static int str_gsub (lua_State *L) {
643 e = match(&ms, src, p); 663 e = match(&ms, src, p);
644 if (e) { 664 if (e) {
645 n++; 665 n++;
646 add_s(&ms, &b, src, e); 666 add_value(&ms, &b, src, e);
647 } 667 }
648 if (e && e>src) /* non empty match? */ 668 if (e && e>src) /* non empty match? */
649 src = e; /* skip it */ 669 src = e; /* skip it */