diff options
| -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 */ |
