00001
00002 #include <squirrel.h>
00003 #include <sqstdstring.h>
00004 #include <string.h>
00005 #include <stdlib.h>
00006 #include <stdio.h>
00007 #include <ctype.h>
00008 #include <assert.h>
00009 #include <stdarg.h>
00010
00011 #ifdef SQUNICODE
00012 #define scstrchr wcschr
00013 #define scatoi _wtoi
00014 #define scstrtok wcstok
00015 #else
00016 #define scstrchr strchr
00017 #define scatoi atoi
00018 #define scstrtok strtok
00019 #endif
00020 #define MAX_FORMAT_LEN 20
00021 #define MAX_WFORMAT_LEN 3
00022 #define ADDITIONAL_FORMAT_SPACE (100*sizeof(SQChar))
00023
00024 static SQInteger validate_format(HSQUIRRELVM v, SQChar *fmt, const SQChar *src, SQInteger n,SQInteger &width)
00025 {
00026 SQChar swidth[MAX_WFORMAT_LEN];
00027 SQInteger wc = 0;
00028 SQInteger start = n;
00029 fmt[0] = '%';
00030 while (scstrchr(_SC("-+ #0"), src[n])) n++;
00031 while (scisdigit(src[n])) {
00032 swidth[wc] = src[n];
00033 n++;
00034 wc++;
00035 if(wc>=MAX_WFORMAT_LEN)
00036 return sq_throwerror(v,_SC("width format too long"));
00037 }
00038 swidth[wc] = '\0';
00039 if(wc > 0) {
00040 width = scatoi(swidth);
00041 }
00042 else
00043 width = 0;
00044 if (src[n] == '.') {
00045 n++;
00046
00047 wc = 0;
00048 while (scisdigit(src[n])) {
00049 swidth[wc] = src[n];
00050 n++;
00051 wc++;
00052 if(wc>=MAX_WFORMAT_LEN)
00053 return sq_throwerror(v,_SC("precision format too long"));
00054 }
00055 swidth[wc] = '\0';
00056 if(wc > 0) {
00057 width += scatoi(swidth);
00058 }
00059 }
00060 if (n-start > MAX_FORMAT_LEN )
00061 return sq_throwerror(v,_SC("format too long"));
00062 memcpy(&fmt[1],&src[start],((n-start)+1)*sizeof(SQChar));
00063 fmt[(n-start)+2] = '\0';
00064 return n;
00065 }
00066
00067
00068
00069
00070
00071
00072
00073
00074 static void _append_string(SQInteger &i, SQChar *dest, SQInteger allocated, const SQChar *fmt, ...)
00075 {
00076 va_list va;
00077 va_start(va, fmt);
00078 i += scvsnprintf(&dest[i],allocated-i,fmt,va);
00079 va_end(va);
00080 }
00081
00082 static SQInteger _string_format(HSQUIRRELVM v)
00083 {
00084 const SQChar *format;
00085 SQChar *dest;
00086 SQChar fmt[MAX_FORMAT_LEN];
00087 sq_getstring(v,2,&format);
00088 SQInteger allocated = (sq_getsize(v,2)+1)*sizeof(SQChar);
00089 dest = sq_getscratchpad(v,allocated);
00090 SQInteger n = 0,i = 0, nparam = 3, w = 0;
00091 while(format[n] != '\0') {
00092 if(format[n] != '%') {
00093 assert(i < allocated);
00094 dest[i++] = format[n];
00095 n++;
00096 }
00097 else if(format[n+1] == '%') {
00098 dest[i++] = '%';
00099 n += 2;
00100 }
00101 else {
00102 n++;
00103 if( nparam > sq_gettop(v) )
00104 return sq_throwerror(v,_SC("not enough paramters for the given format string"));
00105 n = validate_format(v,fmt,format,n,w);
00106 if(n < 0) return -1;
00107 SQInteger addlen = 0;
00108 SQInteger valtype = 0;
00109 const SQChar *ts;
00110 SQInteger ti;
00111 SQFloat tf;
00112 switch(format[n]) {
00113 case 's':
00114 if(SQ_FAILED(sq_getstring(v,nparam,&ts)))
00115 return sq_throwerror(v,_SC("string expected for the specified format"));
00116 addlen = (sq_getsize(v,nparam)*sizeof(SQChar))+((w+1)*sizeof(SQChar));
00117 valtype = 's';
00118 break;
00119 case 'i': case 'd': case 'c':case 'o': case 'u': case 'x': case 'X':
00120 if(SQ_FAILED(sq_getinteger(v,nparam,&ti)))
00121 return sq_throwerror(v,_SC("integer expected for the specified format"));
00122 addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar));
00123 valtype = 'i';
00124 break;
00125 case 'f': case 'g': case 'G': case 'e': case 'E':
00126 if(SQ_FAILED(sq_getfloat(v,nparam,&tf)))
00127 return sq_throwerror(v,_SC("float expected for the specified format"));
00128 addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar));
00129 valtype = 'f';
00130 break;
00131 default:
00132 return sq_throwerror(v,_SC("invalid format"));
00133 }
00134 n++;
00135 allocated += addlen;
00136 dest = sq_getscratchpad(v,allocated);
00137 switch(valtype) {
00138 case 's': _append_string(i,dest,allocated,fmt,ts); break;
00139 case 'i': _append_string(i,dest,allocated,fmt,ti); break;
00140 case 'f': _append_string(i,dest,allocated,fmt,tf); break;
00141 };
00142 nparam ++;
00143 }
00144 }
00145 sq_pushstring(v,dest,i);
00146 return 1;
00147 }
00148
00149 static void __strip_l(const SQChar *str,const SQChar **start)
00150 {
00151 const SQChar *t = str;
00152 while(((*t) != '\0') && scisspace(*t)){ t++; }
00153 *start = t;
00154 }
00155
00156 static void __strip_r(const SQChar *str,SQInteger len,const SQChar **end)
00157 {
00158 if(len == 0) {
00159 *end = str;
00160 return;
00161 }
00162 const SQChar *t = &str[len-1];
00163 while(t != str && scisspace(*t)) { t--; }
00164 *end = t+1;
00165 }
00166
00167 static SQInteger _string_strip(HSQUIRRELVM v)
00168 {
00169 const SQChar *str,*start,*end;
00170 sq_getstring(v,2,&str);
00171 SQInteger len = sq_getsize(v,2);
00172 __strip_l(str,&start);
00173 __strip_r(str,len,&end);
00174 sq_pushstring(v,start,end - start);
00175 return 1;
00176 }
00177
00178 static SQInteger _string_lstrip(HSQUIRRELVM v)
00179 {
00180 const SQChar *str,*start;
00181 sq_getstring(v,2,&str);
00182 __strip_l(str,&start);
00183 sq_pushstring(v,start,-1);
00184 return 1;
00185 }
00186
00187 static SQInteger _string_rstrip(HSQUIRRELVM v)
00188 {
00189 const SQChar *str,*end;
00190 sq_getstring(v,2,&str);
00191 SQInteger len = sq_getsize(v,2);
00192 __strip_r(str,len,&end);
00193 sq_pushstring(v,str,end - str);
00194 return 1;
00195 }
00196
00197 static SQInteger _string_split(HSQUIRRELVM v)
00198 {
00199 const SQChar *str,*seps;
00200 SQChar *stemp,*tok;
00201 sq_getstring(v,2,&str);
00202 sq_getstring(v,3,&seps);
00203 if(sq_getsize(v,3) == 0) return sq_throwerror(v,_SC("empty separators string"));
00204 SQInteger memsize = (sq_getsize(v,2)+1)*sizeof(SQChar);
00205 stemp = sq_getscratchpad(v,memsize);
00206 memcpy(stemp,str,memsize);
00207 tok = scstrtok(stemp,seps);
00208 sq_newarray(v,0);
00209 while( tok != NULL ) {
00210 sq_pushstring(v,tok,-1);
00211 sq_arrayappend(v,-2);
00212 tok = scstrtok( NULL, seps );
00213 }
00214 return 1;
00215 }
00216
00217 #define SETUP_REX(v) \
00218 SQRex *self = NULL; \
00219 sq_getinstanceup(v,1,(SQUserPointer *)&self,0);
00220
00221 static SQInteger _rexobj_releasehook(SQUserPointer p, SQInteger size)
00222 {
00223 SQRex *self = ((SQRex *)p);
00224 sqstd_rex_free(self);
00225 return 1;
00226 }
00227
00228 static SQInteger _regexp_match(HSQUIRRELVM v)
00229 {
00230 SETUP_REX(v);
00231 const SQChar *str;
00232 sq_getstring(v,2,&str);
00233 if(sqstd_rex_match(self,str) == SQTrue)
00234 {
00235 sq_pushbool(v,SQTrue);
00236 return 1;
00237 }
00238 sq_pushbool(v,SQFalse);
00239 return 1;
00240 }
00241
00242 static void _addrexmatch(HSQUIRRELVM v,const SQChar *str,const SQChar *begin,const SQChar *end)
00243 {
00244 sq_newtable(v);
00245 sq_pushstring(v,_SC("begin"),-1);
00246 sq_pushinteger(v,begin - str);
00247 sq_rawset(v,-3);
00248 sq_pushstring(v,_SC("end"),-1);
00249 sq_pushinteger(v,end - str);
00250 sq_rawset(v,-3);
00251 }
00252
00253 static SQInteger _regexp_search(HSQUIRRELVM v)
00254 {
00255 SETUP_REX(v);
00256 const SQChar *str,*begin,*end;
00257 SQInteger start = 0;
00258 sq_getstring(v,2,&str);
00259 if(sq_gettop(v) > 2) sq_getinteger(v,3,&start);
00260 if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) {
00261 _addrexmatch(v,str,begin,end);
00262 return 1;
00263 }
00264 return 0;
00265 }
00266
00267 static SQInteger _regexp_capture(HSQUIRRELVM v)
00268 {
00269 SETUP_REX(v);
00270 const SQChar *str,*begin,*end;
00271 SQInteger start = 0;
00272 sq_getstring(v,2,&str);
00273 if(sq_gettop(v) > 2) sq_getinteger(v,3,&start);
00274 if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) {
00275 SQInteger n = sqstd_rex_getsubexpcount(self);
00276 SQRexMatch match;
00277 sq_newarray(v,0);
00278 for(SQInteger i = 0;i < n; i++) {
00279 sqstd_rex_getsubexp(self,i,&match);
00280 if(match.len > 0)
00281 _addrexmatch(v,str,match.begin,match.begin+match.len);
00282 else
00283 _addrexmatch(v,str,str,str);
00284 sq_arrayappend(v,-2);
00285 }
00286 return 1;
00287 }
00288 return 0;
00289 }
00290
00291 static SQInteger _regexp_subexpcount(HSQUIRRELVM v)
00292 {
00293 SETUP_REX(v);
00294 sq_pushinteger(v,sqstd_rex_getsubexpcount(self));
00295 return 1;
00296 }
00297
00298 static SQInteger _regexp_constructor(HSQUIRRELVM v)
00299 {
00300 const SQChar *error,*pattern;
00301 sq_getstring(v,2,&pattern);
00302 SQRex *rex = sqstd_rex_compile(pattern,&error);
00303 if(!rex) return sq_throwerror(v,error);
00304 sq_setinstanceup(v,1,rex);
00305 sq_setreleasehook(v,1,_rexobj_releasehook);
00306 return 0;
00307 }
00308
00309 static SQInteger _regexp__typeof(HSQUIRRELVM v)
00310 {
00311 sq_pushstring(v,_SC("regexp"),-1);
00312 return 1;
00313 }
00314
00315 #define _DECL_REX_FUNC(name,nparams,pmask) {_SC(#name),_regexp_##name,nparams,pmask}
00316 static SQRegFunction rexobj_funcs[]={
00317 _DECL_REX_FUNC(constructor,2,_SC(".s")),
00318 _DECL_REX_FUNC(search,-2,_SC("xsn")),
00319 _DECL_REX_FUNC(match,2,_SC("xs")),
00320 _DECL_REX_FUNC(capture,-2,_SC("xsn")),
00321 _DECL_REX_FUNC(subexpcount,1,_SC("x")),
00322 _DECL_REX_FUNC(_typeof,1,_SC("x")),
00323 {0,0,0,0}
00324 };
00325
00326 #define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_string_##name,nparams,pmask}
00327 static SQRegFunction stringlib_funcs[]={
00328 _DECL_FUNC(format,-2,_SC(".s")),
00329 _DECL_FUNC(strip,2,_SC(".s")),
00330 _DECL_FUNC(lstrip,2,_SC(".s")),
00331 _DECL_FUNC(rstrip,2,_SC(".s")),
00332 _DECL_FUNC(split,3,_SC(".ss")),
00333 {0,0,0,0}
00334 };
00335
00336
00337 SQInteger sqstd_register_stringlib(HSQUIRRELVM v)
00338 {
00339 sq_pushstring(v,_SC("regexp"),-1);
00340 sq_newclass(v,SQFalse);
00341 SQInteger i = 0;
00342 while(rexobj_funcs[i].name != 0) {
00343 SQRegFunction &f = rexobj_funcs[i];
00344 sq_pushstring(v,f.name,-1);
00345 sq_newclosure(v,f.f,0);
00346 sq_setparamscheck(v,f.nparamscheck,f.typemask);
00347 sq_setnativeclosurename(v,-1,f.name);
00348 sq_createslot(v,-3);
00349 i++;
00350 }
00351 sq_createslot(v,-3);
00352
00353 i = 0;
00354 while(stringlib_funcs[i].name!=0)
00355 {
00356 sq_pushstring(v,stringlib_funcs[i].name,-1);
00357 sq_newclosure(v,stringlib_funcs[i].f,0);
00358 sq_setparamscheck(v,stringlib_funcs[i].nparamscheck,stringlib_funcs[i].typemask);
00359 sq_setnativeclosurename(v,-1,stringlib_funcs[i].name);
00360 sq_createslot(v,-3);
00361 i++;
00362 }
00363 return 1;
00364 }