aboutsummaryrefslogtreecommitdiff
path: root/lauxlib.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-11-09 17:03:52 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-11-09 17:03:52 -0200
commit9eafe9c053ef17a0980ab32082bf229bd58e963b (patch)
treece5af4e070b71c714420817c367cc2b16393a112 /lauxlib.c
parent7f6f70853c8a2730fca2e95d5968ad52cf470bda (diff)
downloadlua-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.
Diffstat (limited to 'lauxlib.c')
-rw-r--r--lauxlib.c81
1 files changed, 59 insertions, 22 deletions
diff --git a/lauxlib.c b/lauxlib.c
index 78dfb4e9..68842a98 100644
--- a/lauxlib.c
+++ b/lauxlib.c
@@ -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*/
506LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { 513static 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*/
528static 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*/
552LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
553 return prepbuffsize(B, sz, -1);
526} 554}
527 555
528 556
529LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { 557LUALIB_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*/
559LUALIB_API void luaL_addvalue (luaL_Buffer *B) { 596LUALIB_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
578LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { 615LUALIB_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/* }====================================================== */