Back to home page

Enduro/X

 
 

    


0001 /* see copyright notice in pscript.h */
0002 #include <pscript.h>
0003 #include <psstdstring.h>
0004 #include <string.h>
0005 #include <stdlib.h>
0006 #include <stdio.h>
0007 #include <ctype.h>
0008 #include <assert.h>
0009 
0010 #define MAX_FORMAT_LEN  20
0011 #define MAX_WFORMAT_LEN 3
0012 #define ADDITIONAL_FORMAT_SPACE (100*sizeof(PSChar))
0013 
0014 static PSBool isfmtchr(PSChar ch)
0015 {
0016     switch(ch) {
0017     case '-': case '+': case ' ': case '#': case '0': return PSTrue;
0018     }
0019     return PSFalse;
0020 }
0021 
0022 static PSInteger validate_format(HPSCRIPTVM v, PSChar *fmt, const PSChar *src, PSInteger n,PSInteger &width)
0023 {
0024     PSChar *dummy;
0025     PSChar swidth[MAX_WFORMAT_LEN];
0026     PSInteger wc = 0;
0027     PSInteger start = n;
0028     fmt[0] = '%';
0029     while (isfmtchr(src[n])) n++;
0030     while (scisdigit(src[n])) {
0031         swidth[wc] = src[n];
0032         n++;
0033         wc++;
0034         if(wc>=MAX_WFORMAT_LEN)
0035             return ps_throwerror(v,_SC("width format too long"));
0036     }
0037     swidth[wc] = '\0';
0038     if(wc > 0) {
0039         width = scstrtol(swidth,&dummy,10);
0040     }
0041     else
0042         width = 0;
0043     if (src[n] == '.') {
0044         n++;
0045 
0046         wc = 0;
0047         while (scisdigit(src[n])) {
0048             swidth[wc] = src[n];
0049             n++;
0050             wc++;
0051             if(wc>=MAX_WFORMAT_LEN)
0052                 return ps_throwerror(v,_SC("precision format too long"));
0053         }
0054         swidth[wc] = '\0';
0055         if(wc > 0) {
0056             width += scstrtol(swidth,&dummy,10);
0057 
0058         }
0059     }
0060     if (n-start > MAX_FORMAT_LEN )
0061         return ps_throwerror(v,_SC("format too long"));
0062     memcpy(&fmt[1],&src[start],((n-start)+1)*sizeof(PSChar));
0063     fmt[(n-start)+2] = '\0';
0064     return n;
0065 }
0066 
0067 PSRESULT psstd_format(HPSCRIPTVM v,PSInteger nformatstringidx,PSInteger *outlen,PSChar **output)
0068 {
0069     const PSChar *format;
0070     PSChar *dest;
0071     PSChar fmt[MAX_FORMAT_LEN];
0072     ps_getstring(v,nformatstringidx,&format);
0073     PSInteger format_size = ps_getsize(v,nformatstringidx);
0074     PSInteger allocated = (format_size+2)*sizeof(PSChar);
0075     dest = ps_getscratchpad(v,allocated);
0076     PSInteger n = 0,i = 0, nparam = nformatstringidx+1, w = 0;
0077     //while(format[n] != '\0')
0078     while(n < format_size)
0079     {
0080         if(format[n] != '%') {
0081             assert(i < allocated);
0082             dest[i++] = format[n];
0083             n++;
0084         }
0085         else if(format[n+1] == '%') { //handles %%
0086                 dest[i++] = '%';
0087                 n += 2;
0088         }
0089         else {
0090             n++;
0091             if( nparam > ps_gettop(v) )
0092                 return ps_throwerror(v,_SC("not enough paramters for the given format string"));
0093             n = validate_format(v,fmt,format,n,w);
0094             if(n < 0) return -1;
0095             PSInteger addlen = 0;
0096             PSInteger valtype = 0;
0097             const PSChar *ts = NULL;
0098             PSInteger ti = 0;
0099             PSFloat tf = 0;
0100             switch(format[n]) {
0101             case 's':
0102                 if(PS_FAILED(ps_getstring(v,nparam,&ts)))
0103                     return ps_throwerror(v,_SC("string expected for the specified format"));
0104                 addlen = (ps_getsize(v,nparam)*sizeof(PSChar))+((w+1)*sizeof(PSChar));
0105                 valtype = 's';
0106                 break;
0107             case 'i': case 'd': case 'o': case 'u':  case 'x':  case 'X':
0108 #ifdef _PS64
0109                 {
0110                 size_t flen = scstrlen(fmt);
0111                 PSInteger fpos = flen - 1;
0112                 PSChar f = fmt[fpos];
0113                 const PSChar *prec = (const PSChar *)_PRINT_INT_PREC;
0114                 while(*prec != _SC('\0')) {
0115                     fmt[fpos++] = *prec++;
0116                 }
0117                 fmt[fpos++] = f;
0118                 fmt[fpos++] = _SC('\0');
0119                 }
0120 #endif
0121             case 'c':
0122                 if(PS_FAILED(ps_getinteger(v,nparam,&ti)))
0123                     return ps_throwerror(v,_SC("integer expected for the specified format"));
0124                 addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(PSChar));
0125                 valtype = 'i';
0126                 break;
0127             case 'f': case 'g': case 'G': case 'e':  case 'E':
0128                 if(PS_FAILED(ps_getfloat(v,nparam,&tf)))
0129                     return ps_throwerror(v,_SC("float expected for the specified format"));
0130                 addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(PSChar));
0131                 valtype = 'f';
0132                 break;
0133             default:
0134                 return ps_throwerror(v,_SC("invalid format"));
0135             }
0136             n++;
0137             allocated += addlen + sizeof(PSChar);
0138             dest = ps_getscratchpad(v,allocated);
0139             switch(valtype) {
0140             case 's': i += scsprintf(&dest[i],allocated,fmt,ts); break;
0141             case 'i': i += scsprintf(&dest[i],allocated,fmt,ti); break;
0142             case 'f': i += scsprintf(&dest[i],allocated,fmt,tf); break;
0143             };
0144             nparam ++;
0145         }
0146     }
0147     *outlen = i;
0148     dest[i] = '\0';
0149     *output = dest;
0150     return PS_OK;
0151 }
0152 
0153 static PSInteger _string_format(HPSCRIPTVM v)
0154 {
0155     PSChar *dest = NULL;
0156     PSInteger length = 0;
0157     if(PS_FAILED(psstd_format(v,2,&length,&dest)))
0158         return -1;
0159     ps_pushstring(v,dest,length);
0160     return 1;
0161 }
0162 
0163 static void __strip_l(const PSChar *str,const PSChar **start)
0164 {
0165     const PSChar *t = str;
0166     while(((*t) != '\0') && scisspace(*t)){ t++; }
0167     *start = t;
0168 }
0169 
0170 static void __strip_r(const PSChar *str,PSInteger len,const PSChar **end)
0171 {
0172     if(len == 0) {
0173         *end = str;
0174         return;
0175     }
0176     const PSChar *t = &str[len-1];
0177     while(t >= str && scisspace(*t)) { t--; }
0178     *end = t + 1;
0179 }
0180 
0181 static PSInteger _string_strip(HPSCRIPTVM v)
0182 {
0183     const PSChar *str,*start,*end;
0184     ps_getstring(v,2,&str);
0185     PSInteger len = ps_getsize(v,2);
0186     __strip_l(str,&start);
0187     __strip_r(str,len,&end);
0188     ps_pushstring(v,start,end - start);
0189     return 1;
0190 }
0191 
0192 static PSInteger _string_lstrip(HPSCRIPTVM v)
0193 {
0194     const PSChar *str,*start;
0195     ps_getstring(v,2,&str);
0196     __strip_l(str,&start);
0197     ps_pushstring(v,start,-1);
0198     return 1;
0199 }
0200 
0201 static PSInteger _string_rstrip(HPSCRIPTVM v)
0202 {
0203     const PSChar *str,*end;
0204     ps_getstring(v,2,&str);
0205     PSInteger len = ps_getsize(v,2);
0206     __strip_r(str,len,&end);
0207     ps_pushstring(v,str,end - str);
0208     return 1;
0209 }
0210 
0211 static PSInteger _string_split(HPSCRIPTVM v)
0212 {
0213     const PSChar *str,*seps;
0214     PSChar *stemp;
0215     ps_getstring(v,2,&str);
0216     ps_getstring(v,3,&seps);
0217     PSInteger sepsize = ps_getsize(v,3);
0218     if(sepsize == 0) return ps_throwerror(v,_SC("empty separators string"));
0219     PSInteger memsize = (ps_getsize(v,2)+1)*sizeof(PSChar);
0220     stemp = ps_getscratchpad(v,memsize);
0221     memcpy(stemp,str,memsize);
0222     PSChar *start = stemp;
0223     PSChar *end = stemp;
0224     ps_newarray(v,0);
0225     while(*end != '\0')
0226     {
0227         PSChar cur = *end;
0228         for(PSInteger i = 0; i < sepsize; i++)
0229         {
0230             if(cur == seps[i])
0231             {
0232                 *end = 0;
0233                 ps_pushstring(v,start,-1);
0234                 ps_arrayappend(v,-2);
0235                 start = end + 1;
0236                 break;
0237             }
0238         }
0239         end++;
0240     }
0241     if(end != start)
0242     {
0243         ps_pushstring(v,start,-1);
0244         ps_arrayappend(v,-2);
0245     }
0246     return 1;
0247 }
0248 
0249 static PSInteger _string_escape(HPSCRIPTVM v)
0250 {
0251     const PSChar *str;
0252     PSChar *dest,*resstr;
0253     PSInteger size;
0254     ps_getstring(v,2,&str);
0255     size = ps_getsize(v,2);
0256     if(size == 0) {
0257         ps_push(v,2);
0258         return 1;
0259     }
0260 #ifdef PSUNICODE
0261 #if WCHAR_SIZE == 2
0262     const PSChar *escpat = _SC("\\x%04x");
0263     const PSInteger maxescsize = 6;
0264 #else //WCHAR_SIZE == 4
0265     const PSChar *escpat = _SC("\\x%08x");
0266     const PSInteger maxescsize = 10;
0267 #endif
0268 #else
0269     const PSChar *escpat = _SC("\\x%02x");
0270     const PSInteger maxescsize = 4;
0271 #endif
0272     PSInteger destcharsize = (size * maxescsize); //assumes every char could be escaped
0273     resstr = dest = (PSChar *)ps_getscratchpad(v,destcharsize * sizeof(PSChar));
0274     PSChar c;
0275     PSChar escch;
0276     PSInteger escaped = 0;
0277     for(int n = 0; n < size; n++){
0278         c = *str++;
0279         escch = 0;
0280         if(scisprint(c) || c == 0) {
0281             switch(c) {
0282             case '\a': escch = 'a'; break;
0283             case '\b': escch = 'b'; break;
0284             case '\t': escch = 't'; break;
0285             case '\n': escch = 'n'; break;
0286             case '\v': escch = 'v'; break;
0287             case '\f': escch = 'f'; break;
0288             case '\r': escch = 'r'; break;
0289             case '\\': escch = '\\'; break;
0290             case '\"': escch = '\"'; break;
0291             case '\'': escch = '\''; break;
0292             case 0: escch = '0'; break;
0293             }
0294             if(escch) {
0295                 *dest++ = '\\';
0296                 *dest++ = escch;
0297                 escaped++;
0298             }
0299             else {
0300                 *dest++ = c;
0301             }
0302         }
0303         else {
0304 
0305             dest += scsprintf(dest, destcharsize, escpat, c);
0306             escaped++;
0307         }
0308     }
0309 
0310     if(escaped) {
0311         ps_pushstring(v,resstr,dest - resstr);
0312     }
0313     else {
0314         ps_push(v,2); //nothing escaped
0315     }
0316     return 1;
0317 }
0318 
0319 static PSInteger _string_startswith(HPSCRIPTVM v)
0320 {
0321     const PSChar *str,*cmp;
0322     ps_getstring(v,2,&str);
0323     ps_getstring(v,3,&cmp);
0324     PSInteger len = ps_getsize(v,2);
0325     PSInteger cmplen = ps_getsize(v,3);
0326     PSBool ret = PSFalse;
0327     if(cmplen <= len) {
0328         ret = memcmp(str,cmp,ps_rsl(cmplen)) == 0 ? PSTrue : PSFalse;
0329     }
0330     ps_pushbool(v,ret);
0331     return 1;
0332 }
0333 
0334 static PSInteger _string_endswith(HPSCRIPTVM v)
0335 {
0336     const PSChar *str,*cmp;
0337     ps_getstring(v,2,&str);
0338     ps_getstring(v,3,&cmp);
0339     PSInteger len = ps_getsize(v,2);
0340     PSInteger cmplen = ps_getsize(v,3);
0341     PSBool ret = PSFalse;
0342     if(cmplen <= len) {
0343         ret = memcmp(&str[len - cmplen],cmp,ps_rsl(cmplen)) == 0 ? PSTrue : PSFalse;
0344     }
0345     ps_pushbool(v,ret);
0346     return 1;
0347 }
0348 
0349 #define SETUP_REX(v) \
0350     PSRex *self = NULL; \
0351     ps_getinstanceup(v,1,(PSUserPointer *)&self,0);
0352 
0353 static PSInteger _rexobj_releasehook(PSUserPointer p, PSInteger PS_UNUSED_ARG(size))
0354 {
0355     PSRex *self = ((PSRex *)p);
0356     psstd_rex_free(self);
0357     return 1;
0358 }
0359 
0360 static PSInteger _regexp_match(HPSCRIPTVM v)
0361 {
0362     SETUP_REX(v);
0363     const PSChar *str;
0364     ps_getstring(v,2,&str);
0365     if(psstd_rex_match(self,str) == PSTrue)
0366     {
0367         ps_pushbool(v,PSTrue);
0368         return 1;
0369     }
0370     ps_pushbool(v,PSFalse);
0371     return 1;
0372 }
0373 
0374 static void _addrexmatch(HPSCRIPTVM v,const PSChar *str,const PSChar *begin,const PSChar *end)
0375 {
0376     ps_newtable(v);
0377     ps_pushstring(v,_SC("begin"),-1);
0378     ps_pushinteger(v,begin - str);
0379     ps_rawset(v,-3);
0380     ps_pushstring(v,_SC("end"),-1);
0381     ps_pushinteger(v,end - str);
0382     ps_rawset(v,-3);
0383 }
0384 
0385 static PSInteger _regexp_search(HPSCRIPTVM v)
0386 {
0387     SETUP_REX(v);
0388     const PSChar *str,*begin,*end;
0389     PSInteger start = 0;
0390     ps_getstring(v,2,&str);
0391     if(ps_gettop(v) > 2) ps_getinteger(v,3,&start);
0392     if(psstd_rex_search(self,str+start,&begin,&end) == PSTrue) {
0393         _addrexmatch(v,str,begin,end);
0394         return 1;
0395     }
0396     return 0;
0397 }
0398 
0399 static PSInteger _regexp_capture(HPSCRIPTVM v)
0400 {
0401     SETUP_REX(v);
0402     const PSChar *str,*begin,*end;
0403     PSInteger start = 0;
0404     ps_getstring(v,2,&str);
0405     if(ps_gettop(v) > 2) ps_getinteger(v,3,&start);
0406     if(psstd_rex_search(self,str+start,&begin,&end) == PSTrue) {
0407         PSInteger n = psstd_rex_getsubexpcount(self);
0408         PSRexMatch match;
0409         ps_newarray(v,0);
0410         for(PSInteger i = 0;i < n; i++) {
0411             psstd_rex_getsubexp(self,i,&match);
0412             if(match.len > 0)
0413                 _addrexmatch(v,str,match.begin,match.begin+match.len);
0414             else
0415                 _addrexmatch(v,str,str,str); //empty match
0416             ps_arrayappend(v,-2);
0417         }
0418         return 1;
0419     }
0420     return 0;
0421 }
0422 
0423 static PSInteger _regexp_subexpcount(HPSCRIPTVM v)
0424 {
0425     SETUP_REX(v);
0426     ps_pushinteger(v,psstd_rex_getsubexpcount(self));
0427     return 1;
0428 }
0429 
0430 static PSInteger _regexp_constructor(HPSCRIPTVM v)
0431 {
0432     const PSChar *error,*pattern;
0433     ps_getstring(v,2,&pattern);
0434     PSRex *rex = psstd_rex_compile(pattern,&error);
0435     if(!rex) return ps_throwerror(v,error);
0436     ps_setinstanceup(v,1,rex);
0437     ps_setreleasehook(v,1,_rexobj_releasehook);
0438     return 0;
0439 }
0440 
0441 static PSInteger _regexp__typeof(HPSCRIPTVM v)
0442 {
0443     ps_pushstring(v,_SC("regexp"),-1);
0444     return 1;
0445 }
0446 
0447 #define _DECL_REX_FUNC(name,nparams,pmask) {_SC(#name),_regexp_##name,nparams,pmask}
0448 static const PSRegFunction rexobj_funcs[]={
0449     _DECL_REX_FUNC(constructor,2,_SC(".s")),
0450     _DECL_REX_FUNC(search,-2,_SC("xsn")),
0451     _DECL_REX_FUNC(match,2,_SC("xs")),
0452     _DECL_REX_FUNC(capture,-2,_SC("xsn")),
0453     _DECL_REX_FUNC(subexpcount,1,_SC("x")),
0454     _DECL_REX_FUNC(_typeof,1,_SC("x")),
0455     {NULL,(PSFUNCTION)0,0,NULL}
0456 };
0457 #undef _DECL_REX_FUNC
0458 
0459 #define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_string_##name,nparams,pmask}
0460 static const PSRegFunction stringlib_funcs[]={
0461     _DECL_FUNC(format,-2,_SC(".s")),
0462     _DECL_FUNC(strip,2,_SC(".s")),
0463     _DECL_FUNC(lstrip,2,_SC(".s")),
0464     _DECL_FUNC(rstrip,2,_SC(".s")),
0465     _DECL_FUNC(split,3,_SC(".ss")),
0466     _DECL_FUNC(escape,2,_SC(".s")),
0467     _DECL_FUNC(startswith,3,_SC(".ss")),
0468     _DECL_FUNC(endswith,3,_SC(".ss")),
0469     {NULL,(PSFUNCTION)0,0,NULL}
0470 };
0471 #undef _DECL_FUNC
0472 
0473 
0474 PSInteger psstd_register_stringlib(HPSCRIPTVM v)
0475 {
0476     ps_pushstring(v,_SC("regexp"),-1);
0477     ps_newclass(v,PSFalse);
0478     PSInteger i = 0;
0479     while(rexobj_funcs[i].name != 0) {
0480         const PSRegFunction &f = rexobj_funcs[i];
0481         ps_pushstring(v,f.name,-1);
0482         ps_newclosure(v,f.f,0);
0483         ps_setparamscheck(v,f.nparamscheck,f.typemask);
0484         ps_setnativeclosurename(v,-1,f.name);
0485         ps_newslot(v,-3,PSFalse);
0486         i++;
0487     }
0488     ps_newslot(v,-3,PSFalse);
0489 
0490     i = 0;
0491     while(stringlib_funcs[i].name!=0)
0492     {
0493         ps_pushstring(v,stringlib_funcs[i].name,-1);
0494         ps_newclosure(v,stringlib_funcs[i].f,0);
0495         ps_setparamscheck(v,stringlib_funcs[i].nparamscheck,stringlib_funcs[i].typemask);
0496         ps_setnativeclosurename(v,-1,stringlib_funcs[i].name);
0497         ps_newslot(v,-3,PSFalse);
0498         i++;
0499     }
0500     return 1;
0501 }