/* * The builtin Math object. * Copyright (c) 1998 New Generation Software (NGS) Oy * * Author: Markku Rossi <mtr@ngs.fi> */ /* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA */ /* * $Source: /tmp/cvsroot-15-2-2007/clamav-devel/libclamav/js/b_math.c,v $ * $Id: b_math.c,v 1.2 2006/10/28 11:27:44 njh Exp $ */ #if HAVE_CONFIG_H #include "clamav-config.h" #endif #ifdef CL_EXPERIMENTAL #include "jsint.h" #include "rentrant.h" /* * Types and definitions. */ #ifndef M_E #define M_E 2.71828182845904523536028747135266250 #endif #ifndef M_LN10 #define M_LN10 2.302585092994046 #endif #ifndef M_LN2 #define M_LN2 0.693147180559945309417232121458176568 #endif #ifndef M_LOG10E #define M_LOG10E 0.434294481903251827651128918916605082 #endif #ifndef M_LOG2E #define M_LOG2E 1.44269504088896340735992468100189214 #endif #ifndef M_PI #define M_PI 3.14159265358979323846264338327950288 #endif #ifndef M_SQRT1_2 #define M_SQRT1_2 0.707106781186547524400844362104849039 #endif #ifndef M_SQRT2 #define M_SQRT2 1.41421356237309504880168872420969808 #endif #define ONE_ARG() \ do { \ JSNode cvt; \ \ if (args->u.vinteger != 1) \ goto argument_error; \ \ js_vm_to_number (vm, &args[1], &cvt); \ if (cvt.type == JS_INTEGER) \ d = (double) cvt.u.vinteger; \ else if (cvt.type == JS_FLOAT) \ d = cvt.u.vfloat; \ else \ { \ /* Must be NaN. */ \ result_return->type = JS_NAN; \ goto done; \ } \ } while (0) #define TWO_ARGS() \ do { \ JSNode cvt; \ \ if (args->u.vinteger != 2) \ goto argument_error; \ \ js_vm_to_number (vm, &args[1], &cvt); \ if (cvt.type == JS_INTEGER) \ d = (double) cvt.u.vinteger; \ else if (cvt.type == JS_FLOAT) \ d = cvt.u.vfloat; \ else \ { \ /* Must be NaN. */ \ result_return->type = JS_NAN; \ goto done; \ } \ \ js_vm_to_number (vm, &args[2], &cvt); \ if (cvt.type == JS_INTEGER) \ d2 = (double) args[1].u.vinteger; \ else if (cvt.type == JS_FLOAT) \ d2 = cvt.u.vfloat; \ else \ { \ /* Must be NaN. */ \ result_return->type = JS_NAN; \ goto done; \ } \ \ } while (0) /* Class context. */ struct math_ctx_st { JSSymbol s_abs; JSSymbol s_acos; JSSymbol s_asin; JSSymbol s_atan; JSSymbol s_atan2; JSSymbol s_ceil; JSSymbol s_cos; JSSymbol s_exp; JSSymbol s_floor; JSSymbol s_log; JSSymbol s_max; JSSymbol s_min; JSSymbol s_pow; JSSymbol s_random; JSSymbol s_round; JSSymbol s_seed; JSSymbol s_sin; JSSymbol s_sqrt; JSSymbol s_tan; JSSymbol s_E; JSSymbol s_LN10; JSSymbol s_LN2; JSSymbol s_LOG10E; JSSymbol s_LOG2E; JSSymbol s_PI; JSSymbol s_SQRT1_2; JSSymbol s_SQRT2; void *drand48_context; }; typedef struct math_ctx_st MathCtx; /* * Static functions. */ /* Method proc. */ static int method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, void *instance_context, JSSymbol method, JSNode *result_return, JSNode *args) { MathCtx *ctx = builtin_info->obj_context; double d, d2; int i; /* The default return value. */ result_return->type = JS_FLOAT; if (method == ctx->s_abs) { ONE_ARG (); result_return->u.vfloat = fabs (d); } /* ********************************************************************** */ else if (method == ctx->s_acos) { ONE_ARG (); result_return->u.vfloat = acos (d); } /* ********************************************************************** */ else if (method == ctx->s_asin) { ONE_ARG (); result_return->u.vfloat = asin (d); } /* ********************************************************************** */ else if (method == ctx->s_atan) { ONE_ARG (); result_return->u.vfloat = atan (d); } /* ********************************************************************** */ else if (method == ctx->s_atan2) { TWO_ARGS (); result_return->u.vfloat = atan2 (d, d2); } /* ********************************************************************** */ else if (method == ctx->s_ceil) { ONE_ARG (); result_return->u.vfloat = ceil (d); } /* ********************************************************************** */ else if (method == ctx->s_cos) { ONE_ARG (); result_return->u.vfloat = cos (d); } /* ********************************************************************** */ else if (method == ctx->s_exp) { ONE_ARG (); result_return->u.vfloat = exp (d); } /* ********************************************************************** */ else if (method == ctx->s_floor) { ONE_ARG (); result_return->u.vfloat = floor (d); } /* ********************************************************************** */ else if (method == ctx->s_log) { ONE_ARG (); result_return->u.vfloat = log (d); } /* ********************************************************************** */ else if (method == ctx->s_max || method == ctx->s_min) { JSNode cvt; if (args->u.vinteger < 1) goto argument_error; /* Take the initial argument. */ js_vm_to_number (vm, &args[1], &cvt); if (cvt.type == JS_NAN) { result_return->type = JS_NAN; goto done; } if (cvt.type == JS_INTEGER) d = (double) cvt.u.vinteger; else d = cvt.u.vfloat; /* Handle the rest. */ for (i = 1; i < args->u.vinteger; i++) { js_vm_to_number (vm, &args[1], &cvt); if (cvt.type == JS_NAN) { result_return->type = JS_NAN; goto done; } if (cvt.type == JS_INTEGER) d2 = (double) cvt.u.vinteger; else d2 = cvt.u.vfloat; if (method == ctx->s_max) { if (d2 > d) d = d2; } else { if (d2 < d) d = d2; } } result_return->type = JS_FLOAT; result_return->u.vfloat = d; } /* ********************************************************************** */ else if (method == ctx->s_pow) { TWO_ARGS (); result_return->u.vfloat = pow (d, d2); } /* ********************************************************************** */ else if (method == ctx->s_random) { if (args->u.vinteger != 0) goto argument_error; /* js_srand48 (ctx->drand48_context, time (NULL)); */ js_drand48 (ctx->drand48_context, &result_return->u.vfloat); } /* ********************************************************************** */ else if (method == ctx->s_round) { ONE_ARG (); result_return->type = JS_INTEGER; result_return->u.vinteger = (long) (d + 0.5); } /* ********************************************************************** */ else if (method == ctx->s_seed) { ONE_ARG (); js_srand48 (ctx->drand48_context, (long) d); result_return->type = JS_UNDEFINED; } /* ********************************************************************** */ else if (method == ctx->s_sin) { ONE_ARG (); result_return->u.vfloat = sin (d); } /* ********************************************************************** */ else if (method == ctx->s_sqrt) { ONE_ARG (); result_return->u.vfloat = sqrt (d); } /* ********************************************************************** */ else if (method == ctx->s_tan) { ONE_ARG (); result_return->u.vfloat = tan (d); } /* ********************************************************************** */ else if (method == vm->syms.s_toString) { js_vm_make_static_string (vm, result_return, "Math", 4); } /* ********************************************************************** */ else return JS_PROPERTY_UNKNOWN; done: return JS_PROPERTY_FOUND; /* * Error handling. */ argument_error: sprintf (vm->error, "Math.%s(): illegal amount of arguments", js_vm_symname (vm, method)); js_vm_error (vm); argument_type_error: sprintf (vm->error, "Math.%s(): illegal argument", js_vm_symname (vm, method)); js_vm_error (vm); /* NOTREACHED. */ return 0; } /* Property proc. */ static int property (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, void *instance_context, JSSymbol property, int set, JSNode *node) { MathCtx *ctx = builtin_info->obj_context; /* The default result is float. */ node->type = JS_FLOAT; if (property == ctx->s_E) { if (set) goto immutable; node->u.vfloat = M_E; } else if (property == ctx->s_LN10) { if (set) goto immutable; node->u.vfloat = M_LN10; } else if (property == ctx->s_LN2) { if (set) goto immutable; node->u.vfloat = M_LN2; } else if (property == ctx->s_LOG10E) { if (set) goto immutable; node->u.vfloat = M_LOG10E; } else if (property == ctx->s_LOG2E) { if (set) goto immutable; node->u.vfloat = M_LOG2E; } else if (property == ctx->s_PI) { if (set) goto immutable; node->u.vfloat = M_PI; } else if (property == ctx->s_SQRT1_2) { if (set) goto immutable; node->u.vfloat = M_SQRT1_2; } else if (property == ctx->s_SQRT2) { if (set) goto immutable; node->u.vfloat = M_SQRT2; } else { if (!set) node->type = JS_UNDEFINED; return JS_PROPERTY_UNKNOWN; } return JS_PROPERTY_FOUND; /* * Error handling. */ immutable: sprintf (vm->error, "Math.%s: immutable property", js_vm_symname (vm, property)); js_vm_error (vm); /* NOTREACHED. */ return 0; } /* * Global functions. */ void js_builtin_Math (JSVirtualMachine *vm) { JSBuiltinInfo *info; MathCtx *ctx; JSNode *n; ctx = js_calloc (vm, 1, sizeof (*ctx)); ctx->s_abs = js_vm_intern (vm, "abs"); ctx->s_acos = js_vm_intern (vm, "acos"); ctx->s_asin = js_vm_intern (vm, "asin"); ctx->s_atan = js_vm_intern (vm, "atan"); ctx->s_atan2 = js_vm_intern (vm, "atan2"); ctx->s_ceil = js_vm_intern (vm, "ceil"); ctx->s_cos = js_vm_intern (vm, "cos"); ctx->s_exp = js_vm_intern (vm, "exp"); ctx->s_floor = js_vm_intern (vm, "floor"); ctx->s_log = js_vm_intern (vm, "log"); ctx->s_max = js_vm_intern (vm, "max"); ctx->s_min = js_vm_intern (vm, "min"); ctx->s_pow = js_vm_intern (vm, "pow"); ctx->s_random = js_vm_intern (vm, "random"); ctx->s_round = js_vm_intern (vm, "round"); ctx->s_seed = js_vm_intern (vm, "seed"); ctx->s_sin = js_vm_intern (vm, "sin"); ctx->s_sqrt = js_vm_intern (vm, "sqrt"); ctx->s_tan = js_vm_intern (vm, "tan"); ctx->s_E = js_vm_intern (vm, "E"); ctx->s_LN10 = js_vm_intern (vm, "LN10"); ctx->s_LN2 = js_vm_intern (vm, "LN2"); ctx->s_LOG10E = js_vm_intern (vm, "LOG10E"); ctx->s_LOG2E = js_vm_intern (vm, "LOG2E"); ctx->s_PI = js_vm_intern (vm, "PI"); ctx->s_SQRT1_2 = js_vm_intern (vm, "SQRT1_2"); ctx->s_SQRT2 = js_vm_intern (vm, "SQRT2"); ctx->drand48_context = js_drand48_create (vm); /* Object information. */ info = js_vm_builtin_info_create (vm); info->method_proc = method; info->property_proc = property; info->obj_context = ctx; info->obj_context_delete = js_free; /* Define it. */ n = &vm->globals[js_vm_intern (vm, "Math")]; js_vm_builtin_create (vm, n, info, NULL); } #endif /*CL_EXPERIMENTAL*/