sqstdstring.cpp

00001 /* see copyright notice in squirrel.h */
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  * Little hack to remove the "format not a string literal, argument types not checked" warning.
00069  * This check has been added to OpenTTD to make sure that nobody passes wrong string literals,
00070  * but three lines in Squirrel have a little problem with those. Therefor we use this hack
00071  * which basically uses vsnprintf instead of sprintf as vsnprintf is not testing for the right
00072  * string literal at compile time.
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] == '%') { //handles %%
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); //empty match
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 }

Generated on Sun Mar 15 22:49:43 2009 for openttd by  doxygen 1.5.6