Browse Source

support for strings with '\0'

Roberto Ierusalimschy 27 năm trước cách đây
mục cha
commit
88a2023c32
14 tập tin đã thay đổi với 236 bổ sung156 xóa
  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();