diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2005-10-23 15:46:30 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2005-10-23 15:46:30 -0200 |
commit | 62367dda449d2eb3c28b686664b920808ff0f334 (patch) | |
tree | a58a271218d8106240bcb25519fc522e0b6e3fac | |
parent | 056b6a8ef480ab72a5705f2e77a3e95f7d8b2218 (diff) | |
download | lua-62367dda449d2eb3c28b686664b920808ff0f334.tar.gz lua-62367dda449d2eb3c28b686664b920808ff0f334.tar.bz2 lua-62367dda449d2eb3c28b686664b920808ff0f334.zip |
string.gsub accepts a table as the replacement value
-rw-r--r-- | lstrlib.c | 124 |
1 files changed, 72 insertions, 52 deletions
@@ -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 | ||
465 | static void push_onecapture (MatchState *ms, int i) { | 465 | static 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 | ||
475 | static int push_captures (MatchState *ms, const char *s, const char *e) { | 484 | static 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 | ||
585 | static void add_s (MatchState *ms, luaL_Buffer *b, | 589 | static 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); | 611 | static 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 */ |