From 88a2023c3285c4514519158fba90e644fc6ffca3 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Fri, 6 Mar 1998 13:54:42 -0300 Subject: [PATCH] support for strings with '\0' --- lapi.c | 30 +++++++++----- lauxlib.c | 9 +++-- lauxlib.h | 9 +++-- lbuffer.c | 6 ++- lbuiltin.c | 25 +++++------- lgc.c | 6 +-- liolib.c | 30 ++++++++------ llex.c | 6 +-- lobject.h | 9 +++-- lstring.c | 116 ++++++++++++++++++++++++++++++++++------------------- lstring.h | 3 +- lstrlib.c | 102 +++++++++++++++++++++++----------------------- lua.h | 4 +- lvm.c | 41 ++++++++++++++----- 14 files changed, 238 insertions(+), 158 deletions(-) diff --git a/lapi.c b/lapi.c index 8528dd65..5f1a81ba 100644 --- a/lapi.c +++ b/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 1.20 1998/01/27 19:13:45 roberto Exp roberto $ +** $Id: lapi.c,v 1.21 1998/02/12 19:23:32 roberto Exp roberto $ ** Lua API ** See Copyright Notice in lua.h */ @@ -219,7 +219,7 @@ lua_Object lua_getglobal (char *name) lua_Object lua_rawgetglobal (char *name) { TaggedString *ts = luaS_new(name); - return put_luaObject(&ts->u.globalval); + return put_luaObject(&ts->u.s.globalval); } @@ -293,6 +293,14 @@ char *lua_getstring (lua_Object object) else return (svalue(Address(object))); } +long lua_getstrlen (lua_Object object) +{ + luaC_checkGC(); /* "tostring" may create a new string */ + if (object == LUA_NOOBJECT || tostring(Address(object))) + return 0L; + else return (tsvalue(Address(object))->u.s.len); +} + void *lua_getuserdata (lua_Object object) { if (object == LUA_NOOBJECT || ttype(Address(object)) != LUA_T_USERDATA) @@ -321,16 +329,20 @@ void lua_pushnumber (double n) incr_top; } +void lua_pushlstr (char *s, long len) +{ + tsvalue(L->stack.top) = luaS_newlstr(s, len); + ttype(L->stack.top) = LUA_T_STRING; + incr_top; + luaC_checkGC(); +} + void lua_pushstring (char *s) { if (s == NULL) - ttype(L->stack.top) = LUA_T_NIL; - else { - tsvalue(L->stack.top) = luaS_new(s); - ttype(L->stack.top) = LUA_T_STRING; - } - incr_top; - luaC_checkGC(); + lua_pushnil(); + else + lua_pushlstr(s, strlen(s)); } void lua_pushCclosure (lua_CFunction fn, int n) diff --git a/lauxlib.c b/lauxlib.c index 6de9c2bf..f94c9836 100644 --- a/lauxlib.c +++ b/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.8 1998/01/09 15:06:07 roberto Exp $ +** $Id: lauxlib.c,v 1.8 1998/01/09 15:09:53 roberto Exp roberto $ ** Auxiliar functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -31,17 +31,18 @@ void luaL_argerror (int numarg, char *extramsg) numarg, funcname, extramsg); } -char *luaL_check_string (int numArg) +char *luaL_check_lstr (int numArg, long *len) { lua_Object o = lua_getparam(numArg); luaL_arg_check(lua_isstring(o), numArg, "string expected"); + if (len) *len = lua_getstrlen(o); return lua_getstring(o); } -char *luaL_opt_string (int numArg, char *def) +char *luaL_opt_lstr (int numArg, char *def, long *len) { return (lua_getparam(numArg) == LUA_NOOBJECT) ? def : - luaL_check_string(numArg); + luaL_check_lstr(numArg, len); } double luaL_check_number (int numArg) diff --git a/lauxlib.h b/lauxlib.h index 4fe65c99..0e150d25 100644 --- a/lauxlib.h +++ b/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.5 1997/12/17 20:48:58 roberto Exp roberto $ +** $Id: lauxlib.h,v 1.6 1998/01/09 15:06:07 roberto Exp roberto $ ** Auxiliar functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -23,8 +23,10 @@ struct luaL_reg { void luaL_openlib (struct luaL_reg *l, int n); void luaL_argerror (int numarg, char *extramsg); -char *luaL_check_string (int numArg); -char *luaL_opt_string (int numArg, char *def); +#define luaL_check_string(n) (luaL_check_lstr((n), NULL)) +char *luaL_check_lstr (int numArg, long *len); +#define luaL_opt_string(n, d) (luaL_opt_lstr((n), (d), NULL)) +char *luaL_opt_lstr (int numArg, char *def, long *len); double luaL_check_number (int numArg); double luaL_opt_number (int numArg, double def); lua_Object luaL_functionarg (int arg); @@ -34,6 +36,7 @@ void luaL_verror (char *fmt, ...); char *luaL_openspace (int size); void luaL_resetbuffer (void); void luaL_addchar (int c); +int luaL_getsize (void); void luaL_addsize (int n); int luaL_newbuffer (int size); void luaL_oldbuffer (int old); diff --git a/lbuffer.c b/lbuffer.c index 04820736..d5aa8c98 100644 --- a/lbuffer.c +++ b/lbuffer.c @@ -1,5 +1,5 @@ /* -** $Id: $ +** $Id: lbuffer.c,v 1.1 1997/12/23 19:24:36 roberto Exp roberto $ ** Auxiliar functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -57,6 +57,10 @@ void luaL_addsize (int n) L->Mbuffnext += n; } +int luaL_getsize (void) +{ + return L->Mbuffnext-(L->Mbuffbase-L->Mbuffer); +} int luaL_newbuffer (int size) { diff --git a/lbuiltin.c b/lbuiltin.c index 1d26b86e..683bbd9b 100644 --- a/lbuiltin.c +++ b/lbuiltin.c @@ -1,5 +1,5 @@ /* -** $Id: lbuiltin.c,v 1.24 1998/02/12 19:23:32 roberto Exp roberto $ +** $Id: lbuiltin.c,v 1.25 1998/02/12 19:27:10 roberto Exp roberto $ ** Built-in functions ** See Copyright Notice in lua.h */ @@ -47,11 +47,11 @@ static void nextvar (void) luaL_arg_check((GCnode *)g != g->head.next, 1, "variable name expected"); g = (TaggedString *)g->head.next; } - while (g && g->u.globalval.ttype == LUA_T_NIL) /* skip globals with nil */ + while (g && g->u.s.globalval.ttype == LUA_T_NIL) /* skip globals with nil */ g = (TaggedString *)g->head.next; if (g) { pushstring(g); - luaA_pushobject(&g->u.globalval); + luaA_pushobject(&g->u.s.globalval); } } @@ -65,12 +65,12 @@ static void foreachvar (void) L->stack.top++; for (g = L->rootglobal.next; g; g = g->next) { TaggedString *s = (TaggedString *)g; - if (s->u.globalval.ttype != LUA_T_NIL) { + if (s->u.s.globalval.ttype != LUA_T_NIL) { ttype(L->stack.stack+name) = LUA_T_STRING; tsvalue(L->stack.stack+name) = s; /* keep s on stack to avoid GC */ luaA_pushobject(&f); pushstring(s); - luaA_pushobject(&s->u.globalval); + luaA_pushobject(&s->u.s.globalval); luaD_call((L->stack.top-L->stack.stack)-2, 1); if (ttype(L->stack.top-1) != LUA_T_NIL) return; @@ -331,22 +331,17 @@ static void copytagmethods (void) static void rawgettable (void) { - lua_Object t = luaL_nonnullarg(1); - lua_Object i = luaL_nonnullarg(2); - lua_pushobject(t); - lua_pushobject(i); + lua_pushobject(luaL_nonnullarg(1)); + lua_pushobject(luaL_nonnullarg(2)); lua_pushobject(lua_rawgettable()); } static void rawsettable (void) { - lua_Object t = luaL_nonnullarg(1); - lua_Object i = luaL_nonnullarg(2); - lua_Object v = luaL_nonnullarg(3); - lua_pushobject(t); - lua_pushobject(i); - lua_pushobject(v); + lua_pushobject(luaL_nonnullarg(1)); + lua_pushobject(luaL_nonnullarg(2)); + lua_pushobject(luaL_nonnullarg(3)); lua_rawsettable(); } diff --git a/lgc.c b/lgc.c index 21550bb7..14b6bceb 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 1.15 1998/01/09 14:44:55 roberto Exp roberto $ +** $Id: lgc.c,v 1.16 1998/01/19 19:49:22 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -213,8 +213,8 @@ static void globalmark (void) { TaggedString *g; for (g=(TaggedString *)L->rootglobal.next; g; g=(TaggedString *)g->head.next) - if (g->u.globalval.ttype != LUA_T_NIL) { - markobject(&g->u.globalval); + if (g->u.s.globalval.ttype != LUA_T_NIL) { + markobject(&g->u.s.globalval); strmark(g); /* cannot collect non nil global variables */ } } diff --git a/liolib.c b/liolib.c index 9ed3e8d8..260625bb 100644 --- a/liolib.c +++ b/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 1.13 1997/12/26 18:38:16 roberto Exp roberto $ +** $Id: liolib.c,v 1.14 1998/01/07 16:26:48 roberto Exp roberto $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -184,7 +184,7 @@ static void io_read (void) { int arg = FIRSTARG; FILE *f = getfileparam(FINPUT, &arg); - char *buff; + int l; char *p = luaL_opt_string(arg, "[^\n]*{\n}"); int inskip = 0; /* to control {skips} */ int c = NEED_OTHER; @@ -204,10 +204,16 @@ static void io_read (void) char *ep; /* get what is next */ int m; /* match result */ if (c == NEED_OTHER) c = getc(f); - m = luaI_singlematch((c == EOF) ? 0 : (char)c, p, &ep); - if (m) { - if (inskip == 0) luaL_addchar(c); - c = NEED_OTHER; + if (c == EOF) { + luaI_singlematch(0, p, &ep); /* to set "ep" */ + m = 0; + } + else { + m = luaI_singlematch((char)c, p, &ep); + if (m) { + if (inskip == 0) luaL_addchar(c); + c = NEED_OTHER; + } } switch (*ep) { case '*': /* repetition */ @@ -225,10 +231,9 @@ static void io_read (void) } break_while: if (c >= 0) /* not EOF nor NEED_OTHER? */ ungetc(c, f); - luaL_addchar(0); - buff = luaL_buffer(); - if (*buff != 0 || *p == 0) /* read something or did not fail? */ - lua_pushstring(buff); + l = luaL_getsize(); + if (l > 0 || *p == 0) /* read something or did not fail? */ + lua_pushlstr(luaL_buffer(), l); } @@ -238,8 +243,9 @@ static void io_write (void) FILE *f = getfileparam(FOUTPUT, &arg); int status = 1; char *s; - while ((s = luaL_opt_string(arg++, NULL)) != NULL) - status = status && (fputs(s, f) != EOF); + long l; + while ((s = luaL_opt_lstr(arg++, NULL, &l)) != NULL) + status = status && (fwrite(s, 1, l, f) == l); pushresult(status); } diff --git a/llex.c b/llex.c index ef023c3f..5cc90045 100644 --- a/llex.c +++ b/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 1.14 1998/01/19 20:18:02 roberto Exp roberto $ +** $Id: llex.c,v 1.15 1998/02/11 20:56:46 roberto Exp roberto $ ** Lexical Analizer ** See Copyright Notice in lua.h */ @@ -358,8 +358,8 @@ int luaY_lex (YYSTYPE *l) } } next(LS); /* skip delimiter */ - save(0); - l->pTStr = luaS_new(L->Mbuffbase+1); + l->pTStr = luaS_newlstr(L->Mbuffbase+1, + L->Mbuffnext-((L->Mbuffbase+1)-L->Mbuffer)); L->Mbuffer[L->Mbuffnext-1] = del; /* restore delimiter */ return STRING; } diff --git a/lobject.h b/lobject.h index 9e1f94d5..9177f03c 100644 --- a/lobject.h +++ b/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 1.15 1998/01/14 13:48:28 roberto Exp roberto $ +** $Id: lobject.h,v 1.16 1998/01/19 19:49:22 roberto Exp roberto $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -95,10 +95,13 @@ typedef struct GCnode { typedef struct TaggedString { GCnode head; - int constindex; /* hint to reuse constants (= -1 if this is a userdata) */ unsigned long hash; + int constindex; /* hint to reuse constants (= -1 if this is a userdata) */ union { - TObject globalval; + struct { + TObject globalval; + long len; /* if this is a string, here is its length */ + } s; struct { int tag; void *v; /* if this is a userdata, here is its value */ diff --git a/lstring.c b/lstring.c index a6e0ca4e..f18d2ff2 100644 --- a/lstring.c +++ b/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 1.10 1998/01/13 18:06:27 roberto Exp roberto $ +** $Id: lstring.c,v 1.11 1998/01/28 16:50:33 roberto Exp roberto $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -21,7 +21,8 @@ -static TaggedString EMPTY = {{NULL, 2}, 0, 0L, {{LUA_T_NIL, {NULL}}}, {0}}; +static TaggedString EMPTY = {{NULL, 2}, 0L, 0, + {{{LUA_T_NIL, {NULL}}, 0L}}, {0}}; void luaS_init (void) @@ -36,20 +37,14 @@ void luaS_init (void) } -static unsigned long hash (char *s, int tag) +static unsigned long hash_s (char *s, long l) { - unsigned long h; - if (tag != LUA_T_STRING) - h = (unsigned long)s; - else { - h = 0; - while (*s) - h = ((h<<5)-h)^(unsigned char)*(s++); - } + unsigned long h = 0; + while (l--) + h = ((h<<5)-h)^(unsigned char)*(s++); return h; } - static int newsize (stringtable *tb) { int size = tb->size; @@ -91,34 +86,38 @@ static void grow (stringtable *tb) } -static TaggedString *newone (char *buff, int tag, unsigned long h) +static TaggedString *newone_s (char *str, long l, unsigned long h) { - TaggedString *ts; - if (tag == LUA_T_STRING) { - long l = strlen(buff); - ts = (TaggedString *)luaM_malloc(sizeof(TaggedString)+l); - strcpy(ts->str, buff); - ts->u.globalval.ttype = LUA_T_NIL; /* initialize global value */ - ts->constindex = 0; - L->nblocks += gcsizestring(l); - } - else { - ts = luaM_new(TaggedString); - ts->u.d.v = buff; - ts->u.d.tag = tag == LUA_ANYTAG ? 0 : tag; - ts->constindex = -1; /* tag -> this is a userdata */ - L->nblocks++; - } + TaggedString *ts = (TaggedString *)luaM_malloc(sizeof(TaggedString)+l); + memcpy(ts->str, str, l); + ts->str[l] = 0; /* ending 0 */ + ts->u.s.globalval.ttype = LUA_T_NIL; /* initialize global value */ + ts->u.s.len = l; + ts->constindex = 0; + L->nblocks += gcsizestring(l); ts->head.marked = 0; ts->head.next = (GCnode *)ts; /* signal it is in no list */ ts->hash = h; return ts; } -static TaggedString *insert (char *buff, int tag, stringtable *tb) +static TaggedString *newone_u (char *buff, int tag, unsigned long h) +{ + TaggedString *ts = luaM_new(TaggedString); + ts->u.d.v = buff; + ts->u.d.tag = (tag == LUA_ANYTAG) ? 0 : tag; + ts->constindex = -1; /* tag -> this is a userdata */ + L->nblocks++; + ts->head.marked = 0; + ts->head.next = (GCnode *)ts; /* signal it is in no list */ + ts->hash = h; + return ts; +} + +static TaggedString *insert_s (char *str, long l, stringtable *tb) { TaggedString *ts; - unsigned long h = hash(buff, tag); + unsigned long h = hash_s(str, l); int size = tb->size; int i; int j = -1; @@ -129,9 +128,9 @@ static TaggedString *insert (char *buff, int tag, stringtable *tb) for (i = h%size; (ts = tb->hash[i]) != NULL; ) { if (ts == &EMPTY) j = i; - else if ((ts->constindex >= 0) ? /* is a string? */ - (tag == LUA_T_STRING && (strcmp(buff, ts->str) == 0)) : - ((tag == ts->u.d.tag || tag == LUA_ANYTAG) && buff == ts->u.d.v)) + else if (ts->constindex >= 0 && + ts->u.s.len == l && + (memcmp(str, ts->str, l) == 0)) return ts; if (++i == size) i=0; } @@ -140,18 +139,53 @@ static TaggedString *insert (char *buff, int tag, stringtable *tb) i = j; else tb->nuse++; - ts = tb->hash[i] = newone(buff, tag, h); + ts = tb->hash[i] = newone_s(str, l, h); + return ts; +} + +static TaggedString *insert_u (void *buff, int tag, stringtable *tb) +{ + TaggedString *ts; + unsigned long h = (unsigned long)buff; + int size = tb->size; + int i; + int j = -1; + if ((long)tb->nuse*3 >= (long)size*2) { + grow(tb); + size = tb->size; + } + for (i = h%size; (ts = tb->hash[i]) != NULL; ) { + if (ts == &EMPTY) + j = i; + else if (ts->constindex < 0 && /* is a udata? */ + (tag == ts->u.d.tag || tag == LUA_ANYTAG) && + buff == ts->u.d.v) + return ts; + if (++i == size) i=0; + } + /* not found */ + if (j != -1) /* is there an EMPTY space? */ + i = j; + else + tb->nuse++; + ts = tb->hash[i] = newone_u(buff, tag, h); return ts; } TaggedString *luaS_createudata (void *udata, int tag) { - return insert(udata, tag, &L->string_root[(unsigned)udata%NUM_HASHS]); + return insert_u(udata, tag, &L->string_root[(unsigned)udata%NUM_HASHS]); +} + +TaggedString *luaS_newlstr (char *str, long l) +{ + int i = (l==0)?0:(unsigned char)str[0]; + return insert_s(str, l, &L->string_root[i%NUM_HASHS]); } TaggedString *luaS_new (char *str) { - return insert(str, LUA_T_STRING, &L->string_root[(unsigned)str[0]%NUM_HASHS]); + return luaS_newlstr(str, strlen(str)); } TaggedString *luaS_newfixedstring (char *str) @@ -167,7 +201,7 @@ void luaS_free (TaggedString *l) { while (l) { TaggedString *next = (TaggedString *)l->head.next; - L->nblocks -= (l->constindex == -1) ? 1 : gcsizestring(strlen(l->str)); + L->nblocks -= (l->constindex == -1) ? 1 : gcsizestring(l->u.s.len); luaM_free(l); l = next; } @@ -253,7 +287,7 @@ void luaS_freeall (void) void luaS_rawsetglobal (TaggedString *ts, TObject *newval) { - ts->u.globalval = *newval; + ts->u.s.globalval = *newval; if (ts->head.next == (GCnode *)ts) { /* is not in list? */ ts->head.next = L->rootglobal.next; L->rootglobal.next = (GCnode *)ts; @@ -265,7 +299,7 @@ char *luaS_travsymbol (int (*fn)(TObject *)) { TaggedString *g; for (g=(TaggedString *)L->rootglobal.next; g; g=(TaggedString *)g->head.next) - if (fn(&g->u.globalval)) + if (fn(&g->u.s.globalval)) return g->str; return NULL; } @@ -274,6 +308,6 @@ char *luaS_travsymbol (int (*fn)(TObject *)) int luaS_globaldefined (char *name) { TaggedString *ts = luaS_new(name); - return ts->u.globalval.ttype != LUA_T_NIL; + return ts->u.s.globalval.ttype != LUA_T_NIL; } diff --git a/lstring.h b/lstring.h index 5f8d01f4..82cdbabb 100644 --- a/lstring.h +++ b/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.5 1997/11/26 18:53:45 roberto Exp roberto $ +** $Id: lstring.h,v 1.6 1997/12/01 20:31:25 roberto Exp roberto $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -15,6 +15,7 @@ void luaS_init (void); TaggedString *luaS_createudata (void *udata, int tag); TaggedString *luaS_collector (void); void luaS_free (TaggedString *l); +TaggedString *luaS_newlstr (char *str, long l); TaggedString *luaS_new (char *str); TaggedString *luaS_newfixedstring (char *str); void luaS_rawsetglobal (TaggedString *ts, TObject *newval); diff --git a/lstrlib.c b/lstrlib.c index a1b061ed..8ddf6428 100644 --- a/lstrlib.c +++ b/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.7 1998/01/09 14:57:43 roberto Exp roberto $ +** $Id: lstrlib.c,v 1.8 1998/01/27 19:11:36 roberto Exp roberto $ ** Standard library for strings and pattern-matching ** See Copyright Notice in lua.h */ @@ -19,83 +19,86 @@ static void addnchar (char *s, int n) { char *b = luaL_openspace(n); - strncpy(b, s, n); + memcpy(b, s, n); luaL_addsize(n); } -static void addstr (char *s) -{ - addnchar(s, strlen(s)); -} - - static void str_len (void) { - lua_pushnumber(strlen(luaL_check_string(1))); + long l; + luaL_check_lstr(1, &l); + lua_pushnumber(l); } static void closeandpush (void) { - luaL_addchar(0); - lua_pushstring(luaL_buffer()); + lua_pushlstr(luaL_buffer(), luaL_getsize()); +} + + +static long posrelat (long pos, long len) +{ + /* relative string position: negative means back from end */ + return (pos>=0) ? pos : len+pos+1; } static void str_sub (void) { - char *s = luaL_check_string(1); - long l = strlen(s); - long start = (long)luaL_check_number(2); - long end = (long)luaL_opt_number(3, -1); - if (start < 0) start = l+start+1; - if (end < 0) end = l+end+1; - if (1 <= start && start <= end && end <= l) { - luaL_resetbuffer(); - addnchar(s+start-1, end-start+1); - closeandpush(); - } + long l; + char *s = luaL_check_lstr(1, &l); + long start = posrelat(luaL_check_number(2), l); + long end = posrelat(luaL_opt_number(3, -1), l); + if (1 <= start && start <= end && end <= l) + lua_pushlstr(s+start-1, end-start+1); else lua_pushstring(""); } static void str_lower (void) { - char *s; + long l; + int i; + char *s = luaL_check_lstr(1, &l); luaL_resetbuffer(); - for (s = luaL_check_string(1); *s; s++) - luaL_addchar(tolower((unsigned char)*s)); + for (i=0; i 0) - addstr(s); + addnchar(s, l); closeandpush(); } static void str_ascii (void) { - char *s = luaL_check_string(1); - long pos = (long)luaL_opt_number(2, 1) - 1; - luaL_arg_check(0<=pos && poslevel; i++) { - int l = cap->capture[i].len; - char *buff = luaL_openspace(l+1); - if (l == -1) lua_error("unfinished capture"); - strncpy(buff, cap->capture[i].init, l); - buff[l] = 0; - lua_pushstring(buff); - } + for (i=0; ilevel; i++) + lua_pushlstr(cap->capture[i].init, cap->capture[i].len); } @@ -163,7 +160,6 @@ static char *bracket_end (char *p) static int matchclass (int c, int cl) { int res; - if (c == 0) return 0; switch (tolower((unsigned char)cl)) { case 'w' : res = isalnum((unsigned char)c); break; case 'd' : res = isdigit((unsigned char)c); break; @@ -184,7 +180,7 @@ int luaI_singlematch (int c, char *p, char **ep) switch (*p) { case '.': *ep = p+1; - return (c != 0); + return 1; case '\0': *ep = p; return 0; @@ -198,7 +194,6 @@ int luaI_singlematch (int c, char *p, char **ep) int sig = *(p+1) == '^' ? (p++, 0) : 1; if (end == NULL) lua_error("incorrect pattern (missing `]')"); *ep = end+1; - if (c == 0) return 0; while (++p < end) { if (*p == ESC) { if (((p+1) < end) && matchclass(c, *++p)) return sig; @@ -254,7 +249,8 @@ static char *matchitem (char *s, char *p, struct Capture *cap, char **ep) } else p--; /* and go through */ } - return (luaI_singlematch(*s, p, ep) ? s+1 : NULL); + /* "luaI_singlematch" sets "ep" (so must be called even when *s == 0) */ + return (luaI_singlematch(*s, p, ep) && *s) ? s+1 : NULL; } @@ -322,10 +318,11 @@ static char *match (char *s, char *p, struct Capture *cap) static void str_find (void) { - char *s = luaL_check_string(1); + long l; + char *s = luaL_check_lstr(1, &l); char *p = luaL_check_string(2); - long init = (long)luaL_opt_number(3, 1) - 1; - luaL_arg_check(0 <= init && init <= strlen(s), 3, "out of range"); + long init = posrelat(luaL_opt_number(3, 1), l) - 1; + luaL_arg_check(0 <= init && init <= l, 3, "out of range"); if (lua_getparam(4) != LUA_NOOBJECT || strpbrk(p, SPECIALS) == NULL) { /* no special caracters? */ char *s2 = strstr(s+init, p); @@ -381,7 +378,10 @@ static void add_s (lua_Object newp, struct Capture *cap) lua_error(NULL); } res = lua_getresult(1); - addstr(lua_isstring(res) ? lua_getstring(res) : ""); + if (lua_isstring(res)) + addnchar(lua_getstring(res), lua_getstrlen(res)); + else + addnchar(NULL, 0); lua_endblock(); } else luaL_arg_check(0, 3, "string or function expected"); @@ -413,7 +413,7 @@ static void str_gsub (void) else break; if (anchor) break; } - addstr(src); + addnchar(src, strlen(src)); closeandpush(); lua_pushnumber(n); /* number of substitutions */ } diff --git a/lua.h b/lua.h index 4e11f987..90661078 100644 --- a/lua.h +++ b/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.14 1998/01/07 16:26:48 roberto Exp roberto $ +** $Id: lua.h,v 1.15 1998/02/12 19:23:32 roberto Exp roberto $ ** Lua - An Extensible Extension Language ** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil ** e-mail: lua@tecgraf.puc-rio.br @@ -90,12 +90,14 @@ int lua_isfunction (lua_Object object); double lua_getnumber (lua_Object object); char *lua_getstring (lua_Object object); +long lua_getstrlen (lua_Object object); lua_CFunction lua_getcfunction (lua_Object object); void *lua_getuserdata (lua_Object object); void lua_pushnil (void); void lua_pushnumber (double n); +void lua_pushlstr (char *s, long len); void lua_pushstring (char *s); void lua_pushCclosure (lua_CFunction fn, int n); void lua_pushusertag (void *u, int tag); diff --git a/lvm.c b/lvm.c index 0119bd12..dba91979 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 1.22 1998/01/12 13:35:37 roberto Exp roberto $ +** $Id: lvm.c,v 1.23 1998/01/14 13:49:15 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -37,13 +37,14 @@ -static TaggedString *strconc (char *l, char *r) +static TaggedString *strconc (TaggedString *l, TaggedString *r) { - size_t nl = strlen(l); - char *buffer = luaL_openspace(nl+strlen(r)+1); - strcpy(buffer, l); - strcpy(buffer+nl, r); - return luaS_new(buffer); + size_t nl = l->u.s.len; + size_t nr = r->u.s.len; + char *buffer = luaL_openspace(nl+nr+1); + memcpy(buffer, l->str, nl); + memcpy(buffer+nl, r->str, nr); + return luaS_newlstr(buffer, nl+nr); } @@ -167,7 +168,7 @@ void luaV_settable (TObject *t, int mode) void luaV_getglobal (TaggedString *ts) { /* WARNING: caller must assure stack space */ - TObject *value = &ts->u.globalval; + TObject *value = &ts->u.s.globalval; TObject *im = luaT_getimbyObj(value, IM_GETGLOBAL); if (ttype(im) == LUA_T_NIL) { /* default behavior */ *L->stack.top++ = *value; @@ -185,7 +186,7 @@ void luaV_getglobal (TaggedString *ts) void luaV_setglobal (TaggedString *ts) { - TObject *oldvalue = &ts->u.globalval; + TObject *oldvalue = &ts->u.s.globalval; TObject *im = luaT_getimbyObj(oldvalue, IM_SETGLOBAL); if (ttype(im) == LUA_T_NIL) /* default behavior */ luaS_rawsetglobal(ts, --L->stack.top); @@ -224,6 +225,23 @@ static void call_arith (IMS event) } +static int strcomp (char *l, long ll, char *r, long lr) +{ + for (;;) { + long temp = strcoll(l, r); + if (temp != 0) return temp; + /* strings are equal up to a '\0' */ + temp = strlen(l); /* index of first '\0' in both strings */ + if (temp == ll) /* l is finished? */ + return (temp == lr) ? 0 : -1; /* l is equal or smaller than r */ + else if (temp == lr) /* r is finished? */ + return 1; /* l is greater than r (because l is not finished) */ + /* both strings longer than temp; go on comparing (after the '\0') */ + temp++; + l += temp; ll -= temp; r += temp; lr -= temp; + } +} + static void comparison (lua_Type ttype_less, lua_Type ttype_equal, lua_Type ttype_great, IMS op) { @@ -234,7 +252,8 @@ static void comparison (lua_Type ttype_less, lua_Type ttype_equal, if (ttype(l) == LUA_T_NUMBER && ttype(r) == LUA_T_NUMBER) result = (nvalue(l) < nvalue(r)) ? -1 : (nvalue(l) == nvalue(r)) ? 0 : 1; else if (ttype(l) == LUA_T_STRING && ttype(r) == LUA_T_STRING) - result = strcoll(svalue(l), svalue(r)); + result = strcomp(svalue(l), tsvalue(l)->u.s.len, + svalue(r), tsvalue(r)->u.s.len); else { call_binTM(op, "unexpected type in comparison"); return; @@ -582,7 +601,7 @@ StkId luaV_execute (Closure *cl, TProtoFunc *tf, StkId base) if (tostring(l) || tostring(r)) call_binTM(IM_CONCAT, "unexpected type for concatenation"); else { - tsvalue(l) = strconc(svalue(l), svalue(r)); + tsvalue(l) = strconc(tsvalue(l), tsvalue(r)); --S->top; } luaC_checkGC();