From 787a78f83e0484c9e9698189982e2f309808fae8 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Mon, 11 Sep 2000 14:38:42 -0300 Subject: [PATCH] new scheme for buffers --- lauxlib.c | 97 +++++++++++++++++++++++++-- lauxlib.h | 47 ++++++++++--- ldo.c | 5 +- lgc.c | 8 ++- liolib.c | 87 ++++++++++++++---------- llex.c | 196 +++++++++++++++++++++++++++++++----------------------- lobject.c | 13 +++- lobject.h | 3 +- lstate.c | 4 +- lstate.h | 4 +- lstrlib.c | 114 +++++++++++++++---------------- lundump.c | 4 +- lvm.c | 5 +- 13 files changed, 376 insertions(+), 211 deletions(-) diff --git a/lauxlib.c b/lauxlib.c index 2c54bd02..84ccb3b9 100644 --- a/lauxlib.c +++ b/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.32 2000/08/29 14:33:31 roberto Exp roberto $ +** $Id: lauxlib.c,v 1.33 2000/08/29 20:43:28 roberto Exp roberto $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -140,8 +140,97 @@ void luaL_chunkid (char *out, const char *source, int len) { } -void luaL_filesource (char *out, const char *filename, int len) { - if (filename == NULL) filename = "(stdin)"; - sprintf(out, "@%.*s", len-2, filename); /* -2 for '@' and '\0' */ +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + + +#define buffempty(B) ((B)->p == (B)->buffer) +#define bufflen(B) ((B)->p - (B)->buffer) +#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B))) + +#define LIMIT (LUA_MINSTACK/2) + + +static int emptybuffer (luaL_Buffer *B) { + size_t l = bufflen(B); + if (l == 0) return 0; /* put nothing on stack */ + else { + lua_pushlstring(B->L, B->buffer, l); + B->p = B->buffer; + B->level++; + return 1; + } +} + + +static void adjuststack (luaL_Buffer *B) { + if (B->level > 1) { + lua_State *L = B->L; + int toget = 1; /* number of levels to concat */ + size_t toplen = lua_strlen(L, -1); + do { + size_t l = lua_strlen(L, -(toget+1)); + if (B->level - toget + 1 >= LIMIT || toplen > l) { + toplen += l; + toget++; + } + else break; + } while (toget < B->level); + if (toget >= 2) { + lua_concat(L, toget); + B->level = B->level - toget + 1; + } + } +} + + +char *luaL_prepbuffer (luaL_Buffer *B) { + if (emptybuffer(B)) + adjuststack(B); + return B->buffer; +} + + +void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { + while (l--) + luaL_putchar(B, *s++); +} + + +void luaL_pushresult (luaL_Buffer *B) { + emptybuffer(B); + if (B->level == 0) + lua_pushlstring(B->L, NULL, 0); + else if (B->level > 1) + lua_concat(B->L, B->level); + B->level = 1; +} + + +void luaL_addvalue (luaL_Buffer *B) { + lua_State *L = B->L; + size_t vl = lua_strlen(L, -1); + if (vl <= bufffree(B)) { /* fit into buffer? */ + memcpy(B->p, lua_tostring(L, -1), vl); /* put it there */ + B->p += vl; + lua_pop(L, 1); /* remove from stack */ + } + else { + if (emptybuffer(B)) + lua_insert(L, -2); /* put buffer before new value */ + B->level++; /* add new value into B stack */ + adjuststack(B); + } +} + + +void luaL_buffinit (lua_State *L, luaL_Buffer *B) { + B->L = L; + B->p = B->buffer; + B->level = 0; } +/* }====================================================== */ diff --git a/lauxlib.h b/lauxlib.h index 8e3fea5c..de717da5 100644 --- a/lauxlib.h +++ b/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.21 2000/08/29 20:43:28 roberto Exp roberto $ +** $Id: lauxlib.h,v 1.22 2000/09/04 18:27:32 roberto Exp roberto $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -10,6 +10,7 @@ #include +#include #include "lua.h" @@ -34,18 +35,8 @@ void luaL_checktype (lua_State *L, int narg, const char *tname); void luaL_verror (lua_State *L, const char *fmt, ...); int luaL_findstring (const char *name, const char *const list[]); void luaL_chunkid (char *out, const char *source, int len); -void luaL_filesource (char *out, const char *filename, int len); -char *luaL_openspace (lua_State *L, size_t size); -void luaL_resetbuffer (lua_State *L); -void luaL_addchar (lua_State *L, int c); -size_t luaL_getsize (lua_State *L); -void luaL_addsize (lua_State *L, size_t n); -size_t luaL_newbuffer (lua_State *L, size_t size); -void luaL_oldbuffer (lua_State *L, size_t old); -char *luaL_buffer (lua_State *L); - /* ** =============================================================== @@ -64,5 +55,39 @@ char *luaL_buffer (lua_State *L); #define luaL_openl(L,a) luaL_openlib(L, a, (sizeof(a)/sizeof(a[0]))) +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + + +#define LUAL_BUFFERSIZE BUFSIZ + + +typedef struct luaL_Buffer { + char *p; /* current position in buffer */ + int level; + lua_State *L; + char buffer[LUAL_BUFFERSIZE]; +} luaL_Buffer; + +#define luaL_putchar(B,c) \ + ((void)((B)->p < &(B)->buffer[LUAL_BUFFERSIZE] || luaL_prepbuffer(B)), \ + (*(B)->p++ = (char)(c))) + +#define luaL_addsize(B,n) ((B)->p += (n)) + +void luaL_buffinit (lua_State *L, luaL_Buffer *B); +char *luaL_prepbuffer (luaL_Buffer *B); +void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l); +void luaL_addvalue (luaL_Buffer *B); +void luaL_pushresult (luaL_Buffer *B); + + +/* }====================================================== */ + + #endif + diff --git a/ldo.c b/ldo.c index a06fa138..1fd993c7 100644 --- a/ldo.c +++ b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 1.92 2000/08/31 13:31:44 roberto Exp roberto $ +** $Id: ldo.c,v 1.93 2000/09/04 18:52:51 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -293,7 +293,8 @@ static int parse_file (lua_State *L, const char *filename) { int c; /* look ahead char */ FILE *f = (filename == NULL) ? stdin : fopen(filename, "r"); if (f == NULL) return LUA_ERRFILE; /* unable to open file */ - luaL_filesource(source, filename, sizeof(source)); + if (filename == NULL) filename = "(stdin)"; + sprintf(source, "@%.*s", (int)sizeof(source)-2, filename); c = fgetc(f); ungetc(c, f); bin = (c == ID_CHUNK); diff --git a/lgc.c b/lgc.c index f6768dd2..5329e558 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 1.63 2000/08/22 17:44:17 roberto Exp roberto $ +** $Id: lgc.c,v 1.64 2000/08/28 17:57:04 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -333,6 +333,8 @@ void luaC_collect (lua_State *L, int all) { } +#define MINBUFFER 256 + long lua_collectgarbage (lua_State *L, long limit) { unsigned long recovered = L->nblocks; /* to subtract `nblocks' after gc */ markall(L); @@ -340,8 +342,8 @@ long lua_collectgarbage (lua_State *L, long limit) { luaC_collect(L, 0); recovered = recovered - L->nblocks; L->GCthreshold = (limit == 0) ? 2*L->nblocks : L->nblocks+limit; - if (L->Mbuffsize > L->Mbuffnext*4) { /* is buffer too big? */ - L->Mbuffsize /= 2; /* still larger than Mbuffnext*2 */ + if (L->Mbuffsize > MINBUFFER*2) { /* is buffer too big? */ + L->Mbuffsize /= 2; /* still larger than MINBUFFER */ luaM_reallocvector(L, L->Mbuffer, L->Mbuffsize, char); } callgcTM(L, &luaO_nilobject); diff --git a/liolib.c b/liolib.c index 885db9bd..db9f36d6 100644 --- a/liolib.c +++ b/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 1.76 2000/08/31 20:23:40 roberto Exp roberto $ +** $Id: liolib.c,v 1.77 2000/09/05 19:33:32 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -263,7 +263,7 @@ static int read_pattern (lua_State *L, FILE *f, const char *p) { if (c == NEED_OTHER) c = getc(f); m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep); if (m) { - if (!inskip) luaL_addchar(L, c); + if (!inskip) luaL_putchar(L, c); c = NEED_OTHER; } switch (*ep) { @@ -274,7 +274,7 @@ static int read_pattern (lua_State *L, FILE *f, const char *p) { while (m) { /* reads the same item until it fails */ c = getc(f); m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep); - if (m && !inskip) luaL_addchar(L, c); + if (m && !inskip) luaL_putchar(L, c); } /* go through to continue reading the pattern */ case '?': /* optional */ @@ -308,53 +308,74 @@ static int read_number (lua_State *L, FILE *f) { } -static void read_word (lua_State *L, FILE *f) { +static int read_word (lua_State *L, FILE *f) { int c; + luaL_Buffer b; + luaL_buffinit(L, &b); do { c = fgetc(f); } while (isspace(c)); /* skip spaces */ while (c != EOF && !isspace(c)) { - luaL_addchar(L, c); + luaL_putchar(&b, c); c = fgetc(f); } ungetc(c, f); + luaL_pushresult(&b); /* close buffer */ + return (lua_strlen(L, 1) > 0); } -#define HUNK_LINE 256 -#define HUNK_FILE BUFSIZ - static int read_line (lua_State *L, FILE *f) { - int n; - char *b; + int n = 0; + luaL_Buffer b; + luaL_buffinit(L, &b); for (;;) { - b = luaL_openspace(L, HUNK_LINE); - if (!fgets(b, HUNK_LINE, f)) return 0; /* read fails */ - n = strlen(b); - if (b[n-1] != '\n') - luaL_addsize(L, n); + char *p = luaL_prepbuffer(&b); + if (!fgets(p, LUAL_BUFFERSIZE, f)) /* read fails? */ + break; + n = strlen(p); + if (p[n-1] != '\n') + luaL_addsize(&b, n); else { - luaL_addsize(L, n-1); /* do not add the `\n' */ + luaL_addsize(&b, n-1); /* do not add the `\n' */ break; } } - return 1; + luaL_pushresult(&b); /* close buffer */ + return (n > 0); /* read something? */ } static void read_file (lua_State *L, FILE *f) { - size_t n; - do { - char *b = luaL_openspace(L, HUNK_FILE); - n = fread(b, sizeof(char), HUNK_FILE, f); - luaL_addsize(L, n); - } while (n==HUNK_FILE); + size_t len = 0; + size_t size = BUFSIZ; + char *buffer = NULL; + for (;;) { + buffer = (char *)realloc(buffer, size); + if (buffer == NULL) + lua_error(L, "not enough memory to read a file"); + len += fread(buffer+len, sizeof(char), size-len, f); + if (len < size) break; /* did not read all it could */ + size *= 2; + } + lua_pushlstring(L, buffer, len); + free(buffer); } static int read_chars (lua_State *L, FILE *f, size_t n) { - char *b = luaL_openspace(L, n); - size_t n1 = fread(b, sizeof(char), n, f); - luaL_addsize(L, n1); - return (n == n1); + char *buffer; + size_t n1; + char statbuff[BUFSIZ]; + if (n <= BUFSIZ) + buffer = statbuff; + else { + buffer = (char *)malloc(n); + if (buffer == NULL) + lua_error(L, "not enough memory to read a file"); + } + n1 = fread(buffer, sizeof(char), n, f); + lua_pushlstring(L, buffer, n1); + if (buffer != statbuff) free(buffer); + return (n1 > 0 || n == 0); } @@ -375,9 +396,7 @@ static int io_read (lua_State *L) { else luaL_checkstack(L, lastarg-firstarg+1, "too many arguments"); for (n = firstarg; n<=lastarg; n++) { - size_t l; int success; - luaL_resetbuffer(L); if (lua_isnumber(L, n)) success = read_chars(L, f, (size_t)lua_tonumber(L, n)); else { @@ -397,8 +416,7 @@ static int io_read (lua_State *L) { success = 1; /* always success */ break; case 'w': /* word */ - read_word(L, f); - success = 0; /* must read something to succeed */ + success = read_word(L, f); break; default: luaL_argerror(L, n, "invalid format"); @@ -406,9 +424,10 @@ static int io_read (lua_State *L) { } } } - l = luaL_getsize(L); - if (!success && l==0) break; /* read fails */ - lua_pushlstring(L, luaL_buffer(L), l); + if (!success) { + lua_pop(L, 1); /* remove last result */ + break; /* read fails */ + } } endloop: return n - firstarg; } diff --git a/llex.c b/llex.c index 6a9039d1..d16cb99f 100644 --- a/llex.c +++ b/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 1.67 2000/08/09 19:16:57 roberto Exp roberto $ +** $Id: llex.c,v 1.68 2000/08/22 20:07:56 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -27,9 +27,6 @@ #define next(LS) (LS->current = zgetc(LS->z)) -#define save(L, c) luaL_addchar(L, c) -#define save_and_next(L, LS) (save(L, LS->current), next(LS)) - /* ORDER RESERVED */ static const char *const token2string [] = { @@ -70,10 +67,8 @@ void luaX_syntaxerror (LexState *ls, const char *s, const char *token) { void luaX_error (LexState *ls, const char *s, int token) { char buff[TOKEN_LEN]; luaX_token2str(token, buff); - if (buff[0] == '\0') { - save(ls->L, '\0'); - luaX_syntaxerror(ls, s, luaL_buffer(ls->L)); - } + if (buff[0] == '\0') + luaX_syntaxerror(ls, s, ls->L->Mbuffer); else luaX_syntaxerror(ls, s, buff); } @@ -96,16 +91,6 @@ static void luaX_invalidchar (LexState *ls, int c) { } -static const char *readname (lua_State *L, LexState *LS) { - luaL_resetbuffer(L); - do { - save_and_next(L, LS); - } while (isalnum(LS->current) || LS->current == '_'); - save(L, '\0'); - return L->Mbuffer+L->Mbuffbase; -} - - static void inclinenumber (LexState *LS) { next(LS); /* skip '\n' */ ++LS->linenumber; @@ -138,61 +123,133 @@ void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source) { */ +/* use Mbuffer to store names, literal strings and numbers */ + +#define EXTRABUFF 128 +#define checkbuffer(L, n, len) if ((len)+(n) > L->Mbuffsize) \ + luaO_openspace(L, (len)+(n)+EXTRABUFF) + +#define save(L, c, l) (L->Mbuffer[l++] = (char)c) +#define save_and_next(L, LS, l) (save(L, LS->current, l), next(LS)) + -static void read_long_string (lua_State *L, LexState *LS) { +static const char *readname (LexState *LS) { + lua_State *L = LS->L; + size_t l = 0; + checkbuffer(L, 10, l); + do { + checkbuffer(L, 10, l); + save_and_next(L, LS, l); + } while (isalnum(LS->current) || LS->current == '_'); + save(L, '\0', l); + return L->Mbuffer; +} + + +/* LUA_NUMBER */ +static void read_number (LexState *LS, int comma) { + lua_State *L = LS->L; + size_t l = 0; + checkbuffer(L, 10, l); + if (comma) save(L, '.', l); + while (isdigit(LS->current)) { + checkbuffer(L, 10, l); + save_and_next(L, LS, l); + } + if (LS->current == '.') { + save_and_next(L, LS, l); + if (LS->current == '.') { + save_and_next(L, LS, l); + save(L, '\0', l); + luaX_error(LS, "ambiguous syntax" + " (decimal point x string concatenation)", TK_NUMBER); + } + } + while (isdigit(LS->current)) { + checkbuffer(L, 10, l); + save_and_next(L, LS, l); + } + if (LS->current == 'e' || LS->current == 'E') { + save_and_next(L, LS, l); /* read 'E' */ + if (LS->current == '+' || LS->current == '-') + save_and_next(L, LS, l); /* optional exponent sign */ + while (isdigit(LS->current)) { + checkbuffer(L, 10, l); + save_and_next(L, LS, l); + } + } + save(L, '\0', l); + if (!luaO_str2d(L->Mbuffer, &LS->t.seminfo.r)) + luaX_error(LS, "malformed number", TK_NUMBER); +} + + +static void read_long_string (LexState *LS) { + lua_State *L = LS->L; int cont = 0; + size_t l = 0; + checkbuffer(L, 10, l); + save(L, '[', l); /* save first '[' */ + save_and_next(L, LS, l); /* pass the second '[' */ for (;;) { + checkbuffer(L, 10, l); switch (LS->current) { case EOZ: + save(L, '\0', l); luaX_error(LS, "unfinished long string", TK_STRING); break; /* to avoid warnings */ case '[': - save_and_next(L, LS); + save_and_next(L, LS, l); if (LS->current == '[') { cont++; - save_and_next(L, LS); + save_and_next(L, LS, l); } continue; case ']': - save_and_next(L, LS); + save_and_next(L, LS, l); if (LS->current == ']') { if (cont == 0) goto endloop; cont--; - save_and_next(L, LS); + save_and_next(L, LS, l); } continue; case '\n': - save(L, '\n'); + save(L, '\n', l); inclinenumber(LS); continue; default: - save_and_next(L, LS); + save_and_next(L, LS, l); } } endloop: - save_and_next(L, LS); /* skip the second ']' */ - LS->t.seminfo.ts = luaS_newlstr(L, L->Mbuffer+(L->Mbuffbase+2), - L->Mbuffnext-L->Mbuffbase-4); + save_and_next(L, LS, l); /* skip the second ']' */ + save(L, '\0', l); + LS->t.seminfo.ts = luaS_newlstr(L, L->Mbuffer+2, l-5); } -static void read_string (lua_State *L, LexState *LS, int del) { - save_and_next(L, LS); +static void read_string (LexState *LS, int del) { + lua_State *L = LS->L; + size_t l = 0; + checkbuffer(L, 10, l); + save_and_next(L, LS, l); while (LS->current != del) { + checkbuffer(L, 10, l); switch (LS->current) { case EOZ: case '\n': + save(L, '\0', l); luaX_error(LS, "unfinished string", TK_STRING); break; /* to avoid warnings */ case '\\': next(LS); /* do not save the '\' */ switch (LS->current) { - case 'a': save(L, '\a'); next(LS); break; - case 'b': save(L, '\b'); next(LS); break; - case 'f': save(L, '\f'); next(LS); break; - case 'n': save(L, '\n'); next(LS); break; - case 'r': save(L, '\r'); next(LS); break; - case 't': save(L, '\t'); next(LS); break; - case 'v': save(L, '\v'); next(LS); break; - case '\n': save(L, '\n'); inclinenumber(LS); break; + case 'a': save(L, '\a', l); next(LS); break; + case 'b': save(L, '\b', l); next(LS); break; + case 'f': save(L, '\f', l); next(LS); break; + case 'n': save(L, '\n', l); next(LS); break; + case 'r': save(L, '\r', l); next(LS); break; + case 't': save(L, '\t', l); next(LS); break; + case 'v': save(L, '\v', l); next(LS); break; + case '\n': save(L, '\n', l); inclinenumber(LS); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { int c = 0; @@ -201,28 +258,28 @@ static void read_string (lua_State *L, LexState *LS, int del) { c = 10*c + (LS->current-'0'); next(LS); } while (++i<3 && isdigit(LS->current)); - if (c != (unsigned char)c) + if (c != (unsigned char)c) { + save(L, '\0', l); luaX_error(LS, "escape sequence too large", TK_STRING); - save(L, c); + } + save(L, c, l); break; } default: /* handles \\, \", \', and \? */ - save(L, LS->current); - next(LS); + save_and_next(L, LS, l); } break; default: - save_and_next(L, LS); + save_and_next(L, LS, l); } } - save_and_next(L, LS); /* skip delimiter */ - LS->t.seminfo.ts = luaS_newlstr(L, L->Mbuffer+(L->Mbuffbase+1), - L->Mbuffnext-L->Mbuffbase-2); + save_and_next(L, LS, l); /* skip delimiter */ + save(L, '\0', l); + LS->t.seminfo.ts = luaS_newlstr(L, L->Mbuffer+1, l-3); } int luaX_lex (LexState *LS) { - lua_State *L = LS->L; for (;;) { switch (LS->current) { @@ -245,12 +302,10 @@ int luaX_lex (LexState *LS) { continue; case '[': - luaL_resetbuffer(L); - save_and_next(L, LS); + next(LS); if (LS->current != '[') return '['; else { - save_and_next(L, LS); /* pass the second '[' */ - read_long_string(L, LS); + read_long_string(LS); return TK_STRING; } @@ -276,13 +331,11 @@ int luaX_lex (LexState *LS) { case '"': case '\'': - luaL_resetbuffer(L); - read_string(L, LS, LS->current); + read_string(LS, LS->current); return TK_STRING; case '.': - luaL_resetbuffer(L); - save_and_next(L, LS); + next(LS); if (LS->current == '.') { next(LS); if (LS->current == '.') { @@ -292,35 +345,14 @@ int luaX_lex (LexState *LS) { else return TK_CONCAT; /* .. */ } else if (!isdigit(LS->current)) return '.'; - else goto fraction; /* LS->current is a digit */ + else { + read_number(LS, 1); + return TK_NUMBER; + } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - luaL_resetbuffer(L); - do { - save_and_next(L, LS); - } while (isdigit(LS->current)); - if (LS->current == '.') { - save_and_next(L, LS); - if (LS->current == '.') { - save(L, '.'); - luaX_error(LS, "ambiguous syntax" - " (decimal point x string concatenation)", TK_NUMBER); - } - } - fraction: /* LUA_NUMBER */ - while (isdigit(LS->current)) - save_and_next(L, LS); - if (LS->current == 'e' || LS->current == 'E') { - save_and_next(L, LS); /* read 'E' */ - if (LS->current == '+' || LS->current == '-') - save_and_next(L, LS); /* optional exponent sign */ - while (isdigit(LS->current)) - save_and_next(L, LS); - } - save(L, '\0'); - if (!luaO_str2d(L->Mbuffer+L->Mbuffbase, &LS->t.seminfo.r)) - luaX_error(LS, "malformed number", TK_NUMBER); + read_number(LS, 0); return TK_NUMBER; case EOZ: @@ -337,7 +369,7 @@ int luaX_lex (LexState *LS) { return c; } tname: { /* identifier or reserved word */ - TString *ts = luaS_new(L, readname(L, LS)); + TString *ts = luaS_new(LS->L, readname(LS)); if (ts->marked >= RESERVEDMARK) /* reserved word? */ return ts->marked-RESERVEDMARK+FIRST_RESERVED; LS->t.seminfo.ts = ts; diff --git a/lobject.c b/lobject.c index c833e921..7f3d71fc 100644 --- a/lobject.c +++ b/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 1.44 2000/08/09 19:16:57 roberto Exp roberto $ +** $Id: lobject.c,v 1.45 2000/08/11 16:17:28 roberto Exp roberto $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -9,7 +9,9 @@ #include "lua.h" +#include "lmem.h" #include "lobject.h" +#include "lstate.h" /* @@ -53,6 +55,15 @@ int luaO_equalObj (const TObject *t1, const TObject *t2) { } +char *luaO_openspace (lua_State *L, size_t n) { + if (n > L->Mbuffsize) { + luaM_reallocvector(L, L->Mbuffer, n, char); + L->Mbuffsize = n; + } + return L->Mbuffer; +} + + static double expten (unsigned int e) { double exp = 10.0; double res = 1.0; diff --git a/lobject.h b/lobject.h index f2d60760..d36391a6 100644 --- a/lobject.h +++ b/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 1.73 2000/08/21 14:34:43 roberto Exp roberto $ +** $Id: lobject.h,v 1.74 2000/08/22 17:44:17 roberto Exp roberto $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -193,6 +193,7 @@ extern const TObject luaO_nilobject; #define luaO_typename(o) luaO_typenames[ttype(o)] lint32 luaO_power2 (lint32 n); +char *luaO_openspace (lua_State *L, size_t n); int luaO_equalObj (const TObject *t1, const TObject *t2); int luaO_str2d (const char *s, Number *result); diff --git a/lstate.c b/lstate.c index f5d5b67c..1e35e467 100644 --- a/lstate.c +++ b/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 1.35 2000/08/31 13:30:39 roberto Exp roberto $ +** $Id: lstate.c,v 1.36 2000/09/05 19:33:32 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -35,9 +35,7 @@ lua_State *lua_newstate (int stacksize) { L->strt.hash = NULL; L->udt.hash = NULL; L->Mbuffer = NULL; - L->Mbuffbase = 0; L->Mbuffsize = 0; - L->Mbuffnext = 0; L->rootproto = NULL; L->rootcl = NULL; L->roottable = NULL; diff --git a/lstate.h b/lstate.h index 65e4c6ef..66ae964d 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 1.36 2000/08/08 20:42:07 roberto Exp roberto $ +** $Id: lstate.h,v 1.37 2000/08/28 17:57:04 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -61,9 +61,7 @@ struct lua_State { StkId Cbase; /* base for current C function */ struct lua_longjmp *errorJmp; /* current error recover point */ char *Mbuffer; /* global buffer */ - size_t Mbuffbase; /* current first position of Mbuffer */ size_t Mbuffsize; /* size of Mbuffer */ - size_t Mbuffnext; /* next position to fill in Mbuffer */ /* global state */ Proto *rootproto; /* list of all prototypes */ Closure *rootcl; /* list of all closures */ diff --git a/lstrlib.c b/lstrlib.c index 6cdd87da..89114666 100644 --- a/lstrlib.c +++ b/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.50 2000/08/31 20:23:40 roberto Exp roberto $ +** $Id: lstrlib.c,v 1.51 2000/09/05 19:33:32 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -18,13 +18,6 @@ -static void addnchar (lua_State *L, const char *s, size_t n) { - char *b = luaL_openspace(L, n); - memcpy(b, s, n); - luaL_addsize(L, n); -} - - static int str_len (lua_State *L) { size_t l; luaL_check_lstr(L, 1, &l); @@ -33,11 +26,6 @@ static int str_len (lua_State *L) { } -static void closeandpush (lua_State *L) { - lua_pushlstring(L, luaL_buffer(L), luaL_getsize(L)); -} - - static long posrelat (long pos, size_t len) { /* relative string position: negative means back from end */ return (pos>=0) ? pos : (long)len+pos+1; @@ -61,11 +49,12 @@ static int str_sub (lua_State *L) { static int str_lower (lua_State *L) { size_t l; size_t i; + luaL_Buffer b; const char *s = luaL_check_lstr(L, 1, &l); - luaL_resetbuffer(L); + luaL_buffinit(L, &b); for (i=0; i 0) - addnchar(L, s, l); - closeandpush(L); + luaL_addlstring(&b, s, l); + luaL_pushresult(&b); return 1; } @@ -106,13 +97,14 @@ static int str_byte (lua_State *L) { static int str_char (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int i; - luaL_resetbuffer(L); + luaL_Buffer b; + luaL_buffinit(L, &b); for (i=1; i<=n; i++) { int c = luaL_check_int(L, i); luaL_arg_check(L, (unsigned char)c == c, i, "invalid value"); - luaL_addchar(L, (unsigned char)c); + luaL_putchar(&b, (unsigned char)c); } - closeandpush(L); + luaL_pushresult(&b); return 1; } @@ -445,43 +437,37 @@ static int str_find (lua_State *L) { } -static void add_s (lua_State *L, struct Capture *cap) { +static void add_s (lua_State *L, luaL_Buffer *b, struct Capture *cap) { if (lua_isstring(L, 3)) { const char *news = lua_tostring(L, 3); size_t l = lua_strlen(L, 3); size_t i; for (i=0; icapture[level].init, cap->capture[level].len); + luaL_addlstring(b, cap->capture[level].init, cap->capture[level].len); } } } } else { /* is a function */ int status; - size_t oldbuff; int n; - const char *s; lua_pushvalue(L, 3); n = push_captures(L, cap); - /* function may use buffer, so save it and create a new one */ - oldbuff = luaL_newbuffer(L, 0); status = lua_call(L, n, 1); - /* restore old buffer */ - luaL_oldbuffer(L, oldbuff); if (status != 0) - lua_error(L, NULL); - s = lua_tostring(L, -1); - if (s) - addnchar(L, lua_tostring(L, -1), lua_strlen(L, -1)); - lua_pop(L, 1); /* pop function result */ + lua_error(L, NULL); /* propagate error */ + if (lua_isstring(L, -1)) + luaL_addvalue(b); /* add return to accumulated result */ + else + lua_pop(L, 1); /* function result is not a string: pop it */ } } @@ -494,10 +480,11 @@ static int str_gsub (lua_State *L) { int anchor = (*p == '^') ? (p++, 1) : 0; int n = 0; struct Capture cap; + luaL_Buffer b; luaL_arg_check(L, lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)), 3, "string or function expected"); - luaL_resetbuffer(L); + luaL_buffinit(L, &b); cap.src_end = src+srcl; while (n < max_s) { const char *e; @@ -505,17 +492,17 @@ static int str_gsub (lua_State *L) { e = match(L, src, p, &cap); if (e) { n++; - add_s(L, &cap); + add_s(L, &b, &cap); } if (e && e>src) /* non empty match? */ src = e; /* skip it */ else if (src < cap.src_end) - luaL_addchar(L, *src++); + luaL_putchar(&b, *src++); else break; if (anchor) break; } - addnchar(L, src, cap.src_end-src); - closeandpush(L); + luaL_addlstring(&b, src, cap.src_end-src); + luaL_pushresult(&b); lua_pushnumber(L, n); /* number of substitutions */ return 2; } @@ -523,40 +510,43 @@ static int str_gsub (lua_State *L) { /* }====================================================== */ -static void luaI_addquoted (lua_State *L, int arg) { +static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) { size_t l; const char *s = luaL_check_lstr(L, arg, &l); - luaL_addchar(L, '"'); + luaL_putchar(b, '"'); while (l--) { switch (*s) { case '"': case '\\': case '\n': - luaL_addchar(L, '\\'); - luaL_addchar(L, *s); + luaL_putchar(b, '\\'); + luaL_putchar(b, *s); break; - case '\0': addnchar(L, "\\000", 4); break; - default: luaL_addchar(L, *s); + case '\0': luaL_addlstring(b, "\\000", 4); break; + default: luaL_putchar(b, *s); } s++; } - luaL_addchar(L, '"'); + luaL_putchar(b, '"'); } +/* maximum size of each formated item (> len(format('%99.99f', -1e308))) */ +#define MAX_ITEM 512 /* maximum size of each format specification (such as '%-099.99d') */ -#define MAX_FORMAT 20 /* arbitrary limit */ +#define MAX_FORMAT 20 static int str_format (lua_State *L) { int arg = 1; const char *strfrmt = luaL_check_string(L, arg); - luaL_resetbuffer(L); + luaL_Buffer b; + luaL_buffinit(L, &b); while (*strfrmt) { if (*strfrmt != '%') - luaL_addchar(L, *strfrmt++); + luaL_putchar(&b, *strfrmt++); else if (*++strfrmt == '%') - luaL_addchar(L, *strfrmt++); /* %% */ + luaL_putchar(&b, *strfrmt++); /* %% */ else { /* format item */ struct Capture cap; char form[MAX_FORMAT]; /* to store the format ('%...') */ - char *buff; /* to store the formatted item */ + char buff[MAX_ITEM]; /* to store the formatted item */ const char *initf = strfrmt; form[0] = '%'; if (isdigit((unsigned char)*initf) && *(initf+1) == '$') { @@ -572,7 +562,6 @@ static int str_format (lua_State *L) { lua_error(L, "invalid format (width or precision too long)"); strncpy(form+1, initf, strfrmt-initf+1); /* +1 to include conversion */ form[strfrmt-initf+2] = 0; - buff = luaL_openspace(L, 512); /* 512 > len(format('%99.99f', -1e308)) */ switch (*strfrmt++) { case 'c': case 'd': case 'i': sprintf(buff, form, luaL_check_int(L, arg)); @@ -584,7 +573,7 @@ static int str_format (lua_State *L) { sprintf(buff, form, luaL_check_number(L, arg)); break; case 'q': - luaI_addquoted(L, arg); + luaI_addquoted(L, &b, arg); continue; /* skip the "addsize" at the end */ case 's': { size_t l; @@ -592,7 +581,8 @@ static int str_format (lua_State *L) { if (cap.capture[1].len == 0 && l >= 100) { /* no precision and string is too long to be formatted; keep original string */ - addnchar(L, s, l); + lua_pushvalue(L, arg); + luaL_addvalue(&b); continue; /* skip the "addsize" at the end */ } else { @@ -603,10 +593,10 @@ static int str_format (lua_State *L) { default: /* also treat cases 'pnLlh' */ lua_error(L, "invalid option in `format'"); } - luaL_addsize(L, strlen(buff)); + luaL_addlstring(&b, buff, strlen(buff)); } } - closeandpush(L); /* push the result */ + luaL_pushresult(&b); return 1; } diff --git a/lundump.c b/lundump.c index b42f441b..95690033 100644 --- a/lundump.c +++ b/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 1.29 2000/06/28 14:12:55 lhf Exp lhf $ +** $Id: lundump.c,v 1.27 2000/09/04 18:53:41 roberto Exp roberto $ ** load bytecodes from files ** See Copyright Notice in lua.h */ @@ -86,7 +86,7 @@ static TString* LoadString (lua_State* L, ZIO* Z, int swap) return NULL; else { - char* s=luaL_openspace(L,size); + char* s=luaO_openspace(L,size); LoadBlock(L,s,size,Z); return luaS_newlstr(L,s,size-1); /* remove trailing '\0' */ } diff --git a/lvm.c b/lvm.c index a8e81dd5..d842b3ba 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 1.133 2000/08/31 21:02:55 roberto Exp roberto $ +** $Id: lvm.c,v 1.134 2000/09/05 19:33:32 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -12,7 +12,6 @@ #include "lua.h" #include "lapi.h" -#include "lauxlib.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" @@ -300,7 +299,7 @@ void luaV_strconc (lua_State *L, int total, StkId top) { n++; } if (tl > MAX_SIZET) lua_error(L, "string size overflow"); - buffer = luaL_openspace(L, tl); + buffer = luaO_openspace(L, tl); tl = 0; for (i=n; i>0; i--) { /* concat all strings */ size_t l = tsvalue(top-i)->u.s.len;