Przeglądaj źródła

On the implementation of string.gsub make checks on the result of sq_get to not go forward if it doesn't succeed.
Add a similar gsub function to regexp, it only works with closure, array or table for replacement, string like "\1 \2" as replacement is on todo list.

mingodad 13 lat temu
rodzic
commit
b43f799998
2 zmienionych plików z 82 dodań i 7 usunięć
  1. 78 1
      sqstdlib/sqstdstring.cpp
  2. 4 6
      squirrel/sqbaselib.cpp

+ 78 - 1
sqstdlib/sqstdstring.cpp

@@ -354,6 +354,82 @@ static SQInteger _regexp_gmatch(HSQUIRRELVM v)
 	return 1;
 }
 
+#include "sqstdblobimpl.h"
+static SQInteger _regexp_gsub(HSQUIRRELVM v)
+{
+	SETUP_REX(v);
+	const SQChar *str;
+	SQInteger str_size;
+	sq_getstring(v,2,&str);
+	str_size = sq_getsize(v, 2);
+	const SQChar *begin,*end;
+	SQBlob blob(0,8192);
+	SQObjectType ptype = sq_gettype(v, 3);
+    const SQChar *replacement;
+    SQInteger replacement_size;
+	while(sqstd_rex_searchrange(self,str, str+str_size,&begin,&end)){
+	    blob.Write(str, begin-str);
+	    SQInteger n = sqstd_rex_getsubexpcount(self);
+	    SQRexMatch match;
+        SQInteger i = 0;
+	    switch(ptype){
+	        case OT_CLOSURE:{
+                sq_pushroottable(v); //this
+                for(;i < n; i++) {
+                    sqstd_rex_getsubexp(self,i,&match);
+                    if(i > 0){ //skip whole match
+                        sq_pushstring(v, match.begin, match.len);
+                    }
+                }
+                i = sq_call(v, n, SQTrue, SQTrue);
+                if(i < 0) return i;
+                if(sq_gettype(v, -1) == OT_STRING){
+                    const SQChar *svalue;
+                    sq_getstring(v, -1, &svalue);
+                    blob.Write(svalue, sq_getsize(v, -1));
+                }
+                sq_poptop(v);
+	        }
+	        break;
+	        case OT_ARRAY:{
+                for(;i < n; i++) {
+                    sqstd_rex_getsubexp(self,i,&match);
+                    if(i > 0){ //skip whole match
+                        sq_pushinteger(v, i-1);
+                        if(SQ_SUCCEEDED(sq_get(v, 3)) &&
+                                SQ_SUCCEEDED(sq_getstr_and_size(v, -1, &replacement, &replacement_size))){
+                            blob.Write(replacement, replacement_size);
+                            sq_pop(v, 1); //remove value
+                        }
+                    }
+                }
+	        }
+	        break;
+	        case OT_TABLE:{
+                for(;i < n; i++) {
+                    sqstd_rex_getsubexp(self,i,&match);
+                    if(i > 0){ //skip whole match
+                        sq_pushstring(v, match.begin, match.len);
+                        if(SQ_SUCCEEDED(sq_get(v, 3)) &&
+                                SQ_SUCCEEDED(sq_getstr_and_size(v, -1, &replacement, &replacement_size))){
+                            blob.Write(replacement, replacement_size);
+                            sq_pop(v, 1); //remove value
+                        }
+                    }
+                }
+	        }
+	        break;
+	        default:
+                return sq_throwerror(v, _SC("gsub only works with closure, array, table for replacement"));
+	    }
+		str_size -= end-str;
+		str = end;
+	}
+    if(str_size) blob.Write(str, str_size);
+	sq_pushstring(v, (const SQChar *)blob.GetBuf(), blob.Len());
+	return 1;
+}
+
 static void _addrexmatch(HSQUIRRELVM v,const SQChar *str,const SQChar *begin,const SQChar *end)
 {
 	sq_newtable(v);
@@ -468,6 +544,7 @@ static SQRegFunction rexobj_funcs[]={
 	_DECL_REX_FUNC(search,-2,_SC("xsn")),
 	_DECL_REX_FUNC(match,2,_SC("xs")),
 	_DECL_REX_FUNC(gmatch,3,_SC("xsc")),
+	_DECL_REX_FUNC(gsub,3,_SC("xs c|a|t")),
 	_DECL_REX_FUNC(capture,-2,_SC("xsn")),
 	_DECL_REX_FUNC(xcapture,-2,_SC("xsn")),
 	_DECL_REX_FUNC(getxcapture,4,_SC("xsna")),
@@ -493,7 +570,7 @@ static SQRegFunction stringlib_funcs[]={
 SQInteger sqstd_register_stringlib(HSQUIRRELVM v)
 {
 	sq_pushstring(v,_SC("regexp"),-1);
-	sq_newtable(v);
+	sq_newclass(v,SQFalse);
 	SQInteger i = 0;
 	while(rexobj_funcs[i].name != 0) {
 		SQRegFunction &f = rexobj_funcs[i];

+ 4 - 6
squirrel/sqbaselib.cpp

@@ -998,28 +998,26 @@ static int process_string_gsub(LuaMatchState *ms, void *udata, char_buffer_st **
         case OT_ARRAY:{
             for(int i=0; i < ms->level; ++i){
                 sq_pushinteger(v, i);
-                sq_get(v, 3);
-                if(SQ_SUCCEEDED(sq_getstr_and_size(v, -1, &str, &str_size))){
+                if(SQ_SUCCEEDED(sq_get(v, 3)) && SQ_SUCCEEDED(sq_getstr_and_size(v, -1, &str, &str_size))){
                     if(!char_buffer_add_str(ms, b, str, str_size)) {
                         result = 0;
                         break;
                     }
+                    sq_pop(v, 1); //remove value
                 }
-                sq_pop(v, 1); //remove value
             }
         }
         break;
         case OT_TABLE:{
             for(int i=0; i < ms->level; ++i){
                 sq_pushstring(v, ms->capture[i].init, ms->capture[i].len);
-                sq_get(v, 3);
-                if(SQ_SUCCEEDED(sq_getstr_and_size(v, -1, &str, &str_size))){
+                if(SQ_SUCCEEDED(sq_get(v, 3)) && SQ_SUCCEEDED(sq_getstr_and_size(v, -1, &str, &str_size))){
                     if(!char_buffer_add_str(ms, b, str, str_size)) {
                         result = 0;
                         break;
                     }
+                    sq_pop(v, 1); //remove value
                 }
-                sq_pop(v, 1); //remove value
             }
         }
     }