Răsfoiți Sursa

support for strings with '\0'

Roberto Ierusalimschy 27 ani în urmă
părinte
comite
88a2023c32
14 a modificat fișierele cu 236 adăugiri și 156 ștergeri
  1. 21 9
      lapi.c
  2. 5 4
      lauxlib.c
  3. 6 3
      lauxlib.h
  4. 5 1
      lbuffer.c
  5. 10 15
      lbuiltin.c
  6. 3 3
      lgc.c
  7. 18 12
      liolib.c
  8. 3 3
      llex.c
  9. 6 3
      lobject.h
  10. 75 41
      lstring.c
  11. 2 1
      lstring.h
  12. 49 49
      lstrlib.c
  13. 3 1
      lua.h
  14. 30 11
      lvm.c

+ 21 - 9
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,18 +329,22 @@ void lua_pushnumber (double n)
   incr_top;
 }
 
-void lua_pushstring (char *s)
+void lua_pushlstr (char *s, long len)
 {
-  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;
-  }
+  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)
+    lua_pushnil();
+  else
+    lua_pushlstr(s, strlen(s));
+}
+
 void lua_pushCclosure (lua_CFunction fn, int n)
 {
   if (fn == NULL)

+ 5 - 4
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)

+ 6 - 3
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);

+ 5 - 1
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)
 {

+ 10 - 15
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();
 }
 

+ 3 - 3
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 */
     }
 }

+ 18 - 12
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);
 }
 

+ 3 - 3
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;
       }

+ 6 - 3
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 */

+ 75 - 41
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,67 @@ 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_s(str, l);
+  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 &&
+             ts->u.s.len == l &&
+             (memcmp(str, ts->str, l) == 0))
+      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_s(str, l, h);
+  return ts;
+}
+
+static TaggedString *insert_u (void *buff, int tag, stringtable *tb)
 {
   TaggedString *ts;
-  unsigned long h = hash(buff, tag);
+  unsigned long h = (unsigned long)buff;
   int size = tb->size;
   int i;
   int j = -1;
@@ -129,9 +157,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 &&  /* is a udata? */
+             (tag == ts->u.d.tag || tag == LUA_ANYTAG) &&
+             buff == ts->u.d.v)
       return ts;
     if (++i == size) i=0;
   }
@@ -140,18 +168,24 @@ 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_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;
 }
 

+ 2 - 1
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);

+ 49 - 49
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)
+static void str_len (void)
 {
-  addnchar(s, strlen(s));
+  long l;
+  luaL_check_lstr(1, &l);
+  lua_pushnumber(l);
 }
 
 
-static void str_len (void)
+static void closeandpush (void)
 {
- lua_pushnumber(strlen(luaL_check_string(1)));
+  lua_pushlstr(luaL_buffer(), luaL_getsize());
 }
 
 
-static void closeandpush (void)
+static long posrelat (long pos, long len)
 {
-  luaL_addchar(0);
-  lua_pushstring(luaL_buffer());
+  /* 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<l; i++)
+    luaL_addchar(tolower((unsigned char)(s[i])));
   closeandpush();
 }
 
 
 static void str_upper (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(toupper((unsigned char)*s));
+  for (i=0; i<l; i++)
+    luaL_addchar(toupper((unsigned char)(s[i])));
   closeandpush();
 }
 
 static void str_rep (void)
 {
-  char *s = luaL_check_string(1);
+  long l;
+  char *s = luaL_check_lstr(1, &l);
   int n = (int)luaL_check_number(2);
   luaL_resetbuffer();
   while (n-- > 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 && pos<strlen(s), 2,  "out of range");
-  lua_pushnumber((unsigned char)s[pos]);
+  long l;
+  char *s = luaL_check_lstr(1, &l);
+  long pos = posrelat(luaL_opt_number(2, 1), l);
+  luaL_arg_check(0<pos && pos<=l, 2,  "out of range");
+  lua_pushnumber((unsigned char)s[pos-1]);
 }
 
 
@@ -124,14 +127,8 @@ struct Capture {
 static void push_captures (struct Capture *cap)
 {
   int i;
-  for (i=0; i<cap->level; 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; i<cap->level; 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 */
 }

+ 3 - 1
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: [email protected]
@@ -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);

+ 30 - 11
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();