/* see copyright notice in squirrel.h */ #include #include #include #include #define SINGLE_ARG_FUNC(_funcname) static SQRESULT math_##_funcname(HSQUIRRELVM v){ \ SQFloat f; \ sq_getfloat(v,2,&f); \ sq_pushfloat(v,(SQFloat)_funcname(f)); \ return 1; \ } #define TWO_ARGS_FUNC(_funcname) static SQRESULT math_##_funcname(HSQUIRRELVM v){ \ SQFloat p1,p2; \ sq_getfloat(v,2,&p1); \ sq_getfloat(v,3,&p2); \ sq_pushfloat(v,(SQFloat)_funcname(p1,p2)); \ return 1; \ } #define BOOL_SINGLE_ARG_FUNC(_funcname) static SQRESULT math_##_funcname(HSQUIRRELVM v){ \ SQFloat f; \ sq_getfloat(v,2,&f); \ sq_pushbool(v,(SQBool)_funcname(f)); \ return 1; \ } static SQRESULT math_srand(HSQUIRRELVM v) { SQInteger i; if(SQ_FAILED(sq_getinteger(v,2,&i))) return sq_throwerror(v,_SC("invalid param")); srand((unsigned int)i); return 0; } static SQRESULT math_rand(HSQUIRRELVM v) { sq_pushinteger(v,rand()); return 1; } static SQRESULT math_random(HSQUIRRELVM v) { SQ_FUNC_VARS(v); /* the `%' avoids the (rare) case of r==1, and is needed also because on some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */ SQFloat r = (SQFloat)(rand()%RAND_MAX) / (SQFloat)RAND_MAX; if (_top_==1) { /* no arguments: range [0,1) */ sq_pushfloat(v, r); } else if (_top_<=3) { /* int range [1,u] or [l,u] */ SQ_GET_INTEGER(v, 2, u); SQ_OPT_INTEGER(v, 3, l, 1); SQFloat d; if(l<=u) return sq_throwerror(v, _SC("interval is empty")); d= floor(r*(u-l+1)); int tmp = d; sq_pushinteger(v, l+tmp); } else return sq_throwerror(v, _SC("wrong number of arguments")); return 1; } static SQRESULT math_abs(HSQUIRRELVM v) { SQInteger n; sq_getinteger(v,2,&n); sq_pushinteger(v,(SQInteger)abs((int)n)); return 1; } SINGLE_ARG_FUNC(sqrt) SINGLE_ARG_FUNC(fabs) SINGLE_ARG_FUNC(sin) SINGLE_ARG_FUNC(cos) SINGLE_ARG_FUNC(asin) SINGLE_ARG_FUNC(acos) SINGLE_ARG_FUNC(log) SINGLE_ARG_FUNC(log10) SINGLE_ARG_FUNC(tan) SINGLE_ARG_FUNC(atan) TWO_ARGS_FUNC(atan2) TWO_ARGS_FUNC(pow) SINGLE_ARG_FUNC(floor) SINGLE_ARG_FUNC(ceil) SINGLE_ARG_FUNC(exp) BOOL_SINGLE_ARG_FUNC(isnan); BOOL_SINGLE_ARG_FUNC(isfinite); //DAD start #include #include #include SQ_OPT_STRING_STRLEN(); /* mathB_roundf: rounds real value x to the d-th digit; patched Dec 22, 2007 for negative values */ static SQRESULT math_roundf (HSQUIRRELVM v) { SQ_FUNC_VARS(v); SQ_GET_FLOAT(v, 2, x); SQ_OPT_INTEGER(v, 3, dec_places, 0); SQFloat dec_factor; if( dec_places>15 || dec_places<0 ) return sq_throwerror(v, _SC("decimal places out of range 0-15")); switch(dec_places){ case 0: dec_factor = 1.0; break; case 1: dec_factor = 10.0; break; case 2: dec_factor = 100.0; break; case 3: dec_factor = 1000.0; break; case 4: dec_factor = 10000.0; break; case 5: dec_factor = 100000.0; break; case 6: dec_factor = 1000000.0; break; default: dec_factor = pow((double)10.0, dec_places); } if (x < 0) sq_pushfloat(v, ceil(dec_factor*x-0.5) / dec_factor); else sq_pushfloat(v, floor(dec_factor*x+0.5) / dec_factor); return 1; } static SQRESULT math_broundf (HSQUIRRELVM v) { SQ_FUNC_VARS(v); SQ_GET_FLOAT(v, 2, num); SQ_OPT_INTEGER(v, 3, dec_places, 0); SQFloat dec_factor, tmp, itmp; int neg; if( dec_places>15 || dec_places<0 ) return sq_throwerror(v, _SC("decimal places out of range 0-15")); neg = num < 0; switch(dec_places){ case 0: dec_factor = 1.0; break; case 1: dec_factor = 10.0; break; case 2: dec_factor = 100.0; break; case 3: dec_factor = 1000.0; break; case 4: dec_factor = 10000.0; break; case 5: dec_factor = 100000.0; break; case 6: dec_factor = 1000000.0; break; default: dec_factor = pow((double)10.0, dec_places); } tmp = num * dec_factor; itmp = floor(tmp + (neg ? -0.5 : 0.5)); // Handle rounding of .5 in a special manner if(tmp - floor(tmp) == 0.5){ tmp = itmp / 2; if(tmp != floor(tmp) ) { // Is itmp odd // Reduce Magnitude by 1 to make even if(neg) itmp++; else itmp--; } } sq_pushfloat(v, itmp / dec_factor); return 1; } static SQChar math_number_format_dec_point[2] = _SC("."); static SQChar math_number_format_thousand_sep[2] = _SC(","); static SQRESULT math_number_format_get_dec_point(HSQUIRRELVM v) { sq_pushstring(v, math_number_format_dec_point, -1); return 1; } static SQRESULT math_number_format_set_dec_point(HSQUIRRELVM v) { SQ_FUNC_VARS_NO_TOP(v); SQ_GET_STRING(v, 2, dec_point); math_number_format_dec_point[0] = *dec_point; math_number_format_dec_point[1] = _SC('\0'); return 0; } static SQRESULT math_number_format_get_thousand_sep(HSQUIRRELVM v) { sq_pushstring(v, math_number_format_thousand_sep, -1); return 1; } static SQRESULT math_number_format_set_thousand_sep(HSQUIRRELVM v) { SQ_FUNC_VARS_NO_TOP(v); SQ_GET_STRING(v, 2, thousand_sep); math_number_format_thousand_sep[0] = *thousand_sep; math_number_format_thousand_sep[1] = '\0'; return 0; } static SQRESULT math_number_format(HSQUIRRELVM v) { SQ_FUNC_VARS(v); SQ_GET_FLOAT(v, 2, d); SQ_OPT_INTEGER(v, 3, dec, 2); SQ_OPT_STRING(v, 4, dec_point, math_number_format_dec_point); SQ_OPT_STRING(v, 5, thousand_sep, math_number_format_thousand_sep); SQChar tmpbuf[64], resbuf[64]; SQChar *s, *t; /* source, target */ SQChar *dp; int integral; size_t tmplen, reslen=0; int count=0; int is_negative=0; int trim_right_zeros=0; if (d < 0) { is_negative = 1; d = -d; } if (dec < 0) { trim_right_zeros = 1; dec = -dec; } int idec = dec; //on 64 bits there is a warning here about SQInteger/int tmplen = scsprintf(tmpbuf, sizeof(tmpbuf), _SC("%.*f"), idec, d); resbuf[0] = _SC('\0'); if (isdigit((int)tmpbuf[0])) { /* find decimal point, if expected */ if (dec) { dp = scstrpbrk(tmpbuf, _SC(".,")); } else { dp = NULL; } /* calculate the length of the return buffer */ if (dp) { integral = dp - tmpbuf; } else { /* no decimal point was found */ integral = tmplen; } /* allow for thousand separators */ if (*thousand_sep) { integral += (integral-1) / 3; } reslen = integral; if (dec) { reslen += dec; if (*dec_point) { reslen++; } } /* add a byte for minus sign */ if (is_negative) { reslen++; } if(sizeof(resbuf) >= reslen+1) { s = tmpbuf+tmplen-1; t = resbuf+reslen; *t-- = '\0'; /* copy the decimal places. * Take care, as the sprintf implementation may return less places than * we requested due to internal buffer limitations */ if (dec) { int declen = dp ? s - dp : 0; int topad = dec > declen ? dec - declen : 0; /* pad with '0's */ while (topad--) { *t-- = '0'; } if (dp) { s -= declen + 1; /* +1 to skip the point */ t -= declen; /* now copy the chars after the point */ memcpy(t + 1, dp + 1, declen); } /* add decimal point */ if (*dec_point) { *t-- = *dec_point; } } /* copy the numbers before the decimal point, adding thousand * separator every three digits */ while(s >= tmpbuf) { *t-- = *s--; if (*thousand_sep && (++count%3)==0 && s>=tmpbuf) { *t-- = *thousand_sep; } } /* and a minus sign, if needed */ if (is_negative) { *t-- = '-'; } /* trim right zeros */ if (*dec_point && trim_right_zeros) { for(t=resbuf+reslen-1; *t != *dec_point; t--){ if (*t == '0') *t = '\0'; else break; } if (*t == *dec_point) *t = '\0'; } } } sq_pushstring(v, resbuf, -1); return 1; } //DAD end #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),math_##name,nparams,tycheck} static const SQRegFunction mathlib_funcs[] = { _DECL_FUNC(sqrt,2,_SC(".n")), _DECL_FUNC(sin,2,_SC(".n")), _DECL_FUNC(cos,2,_SC(".n")), _DECL_FUNC(asin,2,_SC(".n")), _DECL_FUNC(acos,2,_SC(".n")), _DECL_FUNC(log,2,_SC(".n")), _DECL_FUNC(log10,2,_SC(".n")), _DECL_FUNC(tan,2,_SC(".n")), _DECL_FUNC(atan,2,_SC(".n")), _DECL_FUNC(atan2,3,_SC(".nn")), _DECL_FUNC(pow,3,_SC(".nn")), _DECL_FUNC(floor,2,_SC(".n")), _DECL_FUNC(ceil,2,_SC(".n")), _DECL_FUNC(exp,2,_SC(".n")), _DECL_FUNC(srand,2,_SC(".n")), _DECL_FUNC(rand,1,NULL), _DECL_FUNC(random,-1,_SC(".ii")), _DECL_FUNC(fabs,2,_SC(".n")), _DECL_FUNC(abs,2,_SC(".n")), _DECL_FUNC(isnan,2,_SC(".n")), _DECL_FUNC(isfinite,2,_SC(".n")), _DECL_FUNC(roundf,-2,_SC(".ni")), _DECL_FUNC(broundf,-2,_SC(".ni")), _DECL_FUNC(number_format,-2,_SC(".niss")), _DECL_FUNC(number_format_get_dec_point,1,_SC(".")), _DECL_FUNC(number_format_set_dec_point,2,_SC(".s")), _DECL_FUNC(number_format_get_thousand_sep,1,_SC(".")), _DECL_FUNC(number_format_set_thousand_sep,2,_SC(".s")), {NULL,(SQFUNCTION)0,0,NULL} }; #undef _DECL_FUNC #ifndef M_PI #define M_PI (3.14159265358979323846) #endif SQRESULT sqstd_register_mathlib(HSQUIRRELVM v) { sq_pushstring(v,_SC("math"),-1); sq_newtable(v); SQInteger i=0; while(mathlib_funcs[i].name!=0) { sq_pushstring(v,mathlib_funcs[i].name,-1); sq_newclosure(v,mathlib_funcs[i].f,0); sq_setparamscheck(v,mathlib_funcs[i].nparamscheck,mathlib_funcs[i].typemask); sq_setnativeclosurename(v,-1,mathlib_funcs[i].name); sq_newslot(v,-3,SQFalse); i++; } sq_pushstring(v,_SC("RAND_MAX"),-1); sq_pushinteger(v,RAND_MAX); sq_newslot(v,-3,SQFalse); sq_pushstring(v,_SC("PI"),-1); sq_pushfloat(v,(SQFloat)M_PI); sq_newslot(v,-3,SQFalse); sq_newslot(v,-3,SQTrue); //insert math return SQ_OK; }