diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-11-09 17:03:52 -0200 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-11-09 17:03:52 -0200 |
| commit | 9eafe9c053ef17a0980ab32082bf229bd58e963b (patch) | |
| tree | ce5af4e070b71c714420817c367cc2b16393a112 | |
| parent | 7f6f70853c8a2730fca2e95d5968ad52cf470bda (diff) | |
| download | lua-9eafe9c053ef17a0980ab32082bf229bd58e963b.tar.gz lua-9eafe9c053ef17a0980ab32082bf229bd58e963b.tar.bz2 lua-9eafe9c053ef17a0980ab32082bf229bd58e963b.zip | |
New implementation for 'luaL_addvalue'
The function 'luaL_addvalue' (from the buffer system) was rewritten
so that it does not change the position of the box (if present)
in the stack.
| -rw-r--r-- | lauxlib.c | 81 |
1 files changed, 59 insertions, 22 deletions
| @@ -27,6 +27,12 @@ | |||
| 27 | #include "lauxlib.h" | 27 | #include "lauxlib.h" |
| 28 | 28 | ||
| 29 | 29 | ||
| 30 | #if !defined(MAX_SIZET) | ||
| 31 | /* maximum value for size_t */ | ||
| 32 | #define MAX_SIZET ((size_t)(~(size_t)0)) | ||
| 33 | #endif | ||
| 34 | |||
| 35 | |||
| 30 | /* | 36 | /* |
| 31 | ** {====================================================== | 37 | ** {====================================================== |
| 32 | ** Traceback | 38 | ** Traceback |
| @@ -501,34 +507,56 @@ static void *newbox (lua_State *L, size_t newsize) { | |||
| 501 | 507 | ||
| 502 | 508 | ||
| 503 | /* | 509 | /* |
| 504 | ** returns a pointer to a free area with at least 'sz' bytes | 510 | ** Compute new size for buffer 'B', enough to accommodate extra 'sz' |
| 511 | ** bytes. | ||
| 505 | */ | 512 | */ |
| 506 | LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { | 513 | static size_t newbuffsize (luaL_Buffer *B, size_t sz) { |
| 507 | lua_State *L = B->L; | 514 | size_t newsize = B->size * 2; /* double buffer size */ |
| 508 | if (B->size - B->n < sz) { /* not enough space? */ | 515 | if (MAX_SIZET - sz < B->n) /* overflow in (B->n + sz)? */ |
| 516 | return luaL_error(B->L, "buffer too large"); | ||
| 517 | if (newsize < B->n + sz) /* double is not big enough? */ | ||
| 518 | newsize = B->n + sz; | ||
| 519 | return newsize; | ||
| 520 | } | ||
| 521 | |||
| 522 | |||
| 523 | /* | ||
| 524 | ** Returns a pointer to a free area with at least 'sz' bytes in buffer | ||
| 525 | ** 'B'. 'boxidx' is the position in the stack where the buffer's box is | ||
| 526 | ** or should be. | ||
| 527 | */ | ||
| 528 | static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) { | ||
| 529 | if (B->size - B->n >= sz) /* enough space? */ | ||
| 530 | return B->b + B->n; | ||
| 531 | else { | ||
| 532 | lua_State *L = B->L; | ||
| 509 | char *newbuff; | 533 | char *newbuff; |
| 510 | size_t newsize = B->size * 2; /* double buffer size */ | 534 | size_t newsize = newbuffsize(B, sz); |
| 511 | if (newsize - B->n < sz) /* not big enough? */ | ||
| 512 | newsize = B->n + sz; | ||
| 513 | if (newsize < B->n || newsize - B->n < sz) | ||
| 514 | luaL_error(L, "buffer too large"); | ||
| 515 | /* create larger buffer */ | 535 | /* create larger buffer */ |
| 516 | if (buffonstack(B)) | 536 | if (buffonstack(B)) /* buffer already has a box? */ |
| 517 | newbuff = (char *)resizebox(L, -1, newsize); | 537 | newbuff = (char *)resizebox(L, boxidx, newsize); /* resize it */ |
| 518 | else { /* no buffer yet */ | 538 | else { /* no box yet */ |
| 519 | newbuff = (char *)newbox(L, newsize); | 539 | newbuff = (char *)newbox(L, newsize); /* create a new box */ |
| 520 | memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ | 540 | memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ |
| 541 | lua_insert(L, boxidx); /* move box to its intended position */ | ||
| 521 | } | 542 | } |
| 522 | B->b = newbuff; | 543 | B->b = newbuff; |
| 523 | B->size = newsize; | 544 | B->size = newsize; |
| 545 | return newbuff + B->n; | ||
| 524 | } | 546 | } |
| 525 | return &B->b[B->n]; | 547 | } |
| 548 | |||
| 549 | /* | ||
| 550 | ** returns a pointer to a free area with at least 'sz' bytes | ||
| 551 | */ | ||
| 552 | LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { | ||
| 553 | return prepbuffsize(B, sz, -1); | ||
| 526 | } | 554 | } |
| 527 | 555 | ||
| 528 | 556 | ||
| 529 | LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { | 557 | LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { |
| 530 | if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */ | 558 | if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */ |
| 531 | char *b = luaL_prepbuffsize(B, l); | 559 | char *b = prepbuffsize(B, l, -1); |
| 532 | memcpy(b, s, l * sizeof(char)); | 560 | memcpy(b, s, l * sizeof(char)); |
| 533 | luaL_addsize(B, l); | 561 | luaL_addsize(B, l); |
| 534 | } | 562 | } |
| @@ -556,14 +584,23 @@ LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) { | |||
| 556 | } | 584 | } |
| 557 | 585 | ||
| 558 | 586 | ||
| 587 | /* | ||
| 588 | ** 'luaL_addvalue' is the only function in the Buffer system where the | ||
| 589 | ** box (if existent) is not on the top of the stack. So, instead of | ||
| 590 | ** calling 'luaL_addlstring', it replicates the code using -2 as the | ||
| 591 | ** last argument to 'prepbuffsize', signaling that the box is (or will | ||
| 592 | ** be) bellow the string being added to the buffer. (Box creation can | ||
| 593 | ** trigger an emergency GC, so we should not remove the string from the | ||
| 594 | ** stack before we have the space guaranteed.) | ||
| 595 | */ | ||
| 559 | LUALIB_API void luaL_addvalue (luaL_Buffer *B) { | 596 | LUALIB_API void luaL_addvalue (luaL_Buffer *B) { |
| 560 | lua_State *L = B->L; | 597 | lua_State *L = B->L; |
| 561 | size_t l; | 598 | size_t len; |
| 562 | const char *s = lua_tolstring(L, -1, &l); | 599 | const char *s = lua_tolstring(L, -1, &len); |
| 563 | if (buffonstack(B)) | 600 | char *b = prepbuffsize(B, len, -2); |
| 564 | lua_insert(L, -2); /* put value below buffer */ | 601 | memcpy(b, s, len * sizeof(char)); |
| 565 | luaL_addlstring(B, s, l); | 602 | luaL_addsize(B, len); |
| 566 | lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */ | 603 | lua_pop(L, 1); /* pop string */ |
| 567 | } | 604 | } |
| 568 | 605 | ||
| 569 | 606 | ||
| @@ -577,7 +614,7 @@ LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { | |||
| 577 | 614 | ||
| 578 | LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { | 615 | LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { |
| 579 | luaL_buffinit(L, B); | 616 | luaL_buffinit(L, B); |
| 580 | return luaL_prepbuffsize(B, sz); | 617 | return prepbuffsize(B, sz, -1); |
| 581 | } | 618 | } |
| 582 | 619 | ||
| 583 | /* }====================================================== */ | 620 | /* }====================================================== */ |
