2 * Copyright 2008 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "wine/port.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
36 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
37 static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0};
38 static const WCHAR toFixedW[] = {'t','o','F','i','x','e','d',0};
39 static const WCHAR toExponentialW[] = {'t','o','E','x','p','o','n','e','n','t','i','a','l',0};
40 static const WCHAR toPrecisionW[] = {'t','o','P','r','e','c','i','s','i','o','n',0};
41 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
43 #define NUMBER_TOSTRING_BUF_SIZE 64
44 /* ECMA-262 3rd Edition 15.7.4.2 */
45 static HRESULT Number_toString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
46 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
48 NumberInstance *number;
56 if(!is_class(dispex, JSCLASS_NUMBER))
57 return throw_type_error(ctx, ei, IDS_NOT_NUM, NULL);
59 number = (NumberInstance*)dispex;
62 hres = to_int32(ctx, get_arg(dp, 0), ei, &radix);
66 if(radix<2 || radix>36)
67 return throw_type_error(ctx, ei, IDS_INVALID_CALL_ARG, NULL);
70 if(V_VT(&number->num) == VT_I4)
71 val = V_I4(&number->num);
73 val = V_R8(&number->num);
75 if(radix==10 || isnan(val) || isinf(val)) {
76 hres = to_string(ctx, &number->num, ei, &str);
82 DOUBLE integ, frac, log_radix = 0;
83 WCHAR buf[NUMBER_TOSTRING_BUF_SIZE+16];
97 while(integ>=1 && idx<NUMBER_TOSTRING_BUF_SIZE) {
98 buf[idx] = fmod(integ, radix);
99 if(buf[idx]<10) buf[idx] += '0';
100 else buf[idx] += 'a'-10;
105 if(idx<NUMBER_TOSTRING_BUF_SIZE) {
106 INT beg = buf[0]=='-'?1:0;
112 buf[beg++] = buf[end];
117 if(idx != NUMBER_TOSTRING_BUF_SIZE) buf[idx++] = '.';
119 while(frac>0 && idx<NUMBER_TOSTRING_BUF_SIZE) {
121 buf[idx] = fmod(frac, radix);
123 if(buf[idx]<10) buf[idx] += '0';
124 else buf[idx] += 'a'-10;
128 if(idx==NUMBER_TOSTRING_BUF_SIZE && !exp) {
130 idx = (buf[0]=='-') ? 1 : 0;
131 log_radix = floor(log(val)/log(radix));
132 val *= pow(radix, -log_radix);
139 while(buf[idx-1] == '0') idx--;
140 if(buf[idx-1] == '.') idx--;
146 static const WCHAR formatW[] = {'(','e','%','c','%','d',')',0};
150 log_radix = -log_radix;
154 sprintfW(&buf[idx], formatW, ch, (int)log_radix);
157 else buf[idx] = '\0';
159 str = SysAllocString(buf);
161 return E_OUTOFMEMORY;
165 V_VT(retv) = VT_BSTR;
173 static HRESULT Number_toLocaleString(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
174 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
180 static HRESULT Number_toFixed(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
181 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
187 static HRESULT Number_toExponential(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
188 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
194 static HRESULT Number_toPrecision(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
195 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
201 static HRESULT Number_valueOf(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
202 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
206 if(!is_class(dispex, JSCLASS_NUMBER))
207 return throw_type_error(ctx, ei, IDS_NOT_NUM, NULL);
210 NumberInstance *number = (NumberInstance*)dispex;
216 static HRESULT Number_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
217 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
219 NumberInstance *number = (NumberInstance*)dispex;
223 return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL);
224 case DISPATCH_PROPERTYGET:
229 FIXME("flags %x\n", flags);
236 static const builtin_prop_t Number_props[] = {
237 {toExponentialW, Number_toExponential, PROPF_METHOD|1},
238 {toFixedW, Number_toFixed, PROPF_METHOD},
239 {toLocaleStringW, Number_toLocaleString, PROPF_METHOD},
240 {toPrecisionW, Number_toPrecision, PROPF_METHOD|1},
241 {toStringW, Number_toString, PROPF_METHOD|1},
242 {valueOfW, Number_valueOf, PROPF_METHOD}
245 static const builtin_info_t Number_info = {
247 {NULL, Number_value, 0},
248 sizeof(Number_props)/sizeof(*Number_props),
254 static HRESULT NumberConstr_value(script_ctx_t *ctx, DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
255 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
272 hres = to_number(ctx, get_arg(dp, 0), ei, &num);
280 case DISPATCH_CONSTRUCT: {
284 hres = to_number(ctx, get_arg(dp, 0), ei, &num);
292 hres = create_number(ctx, &num, &obj);
296 V_VT(retv) = VT_DISPATCH;
297 V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(obj);
301 FIXME("unimplemented flags %x\n", flags);
308 static HRESULT alloc_number(script_ctx_t *ctx, DispatchEx *object_prototype, NumberInstance **ret)
310 NumberInstance *number;
313 number = heap_alloc_zero(sizeof(NumberInstance));
315 return E_OUTOFMEMORY;
318 hres = init_dispex(&number->dispex, ctx, &Number_info, object_prototype);
320 hres = init_dispex_from_constr(&number->dispex, ctx, &Number_info, ctx->number_constr);
328 HRESULT create_number_constr(script_ctx_t *ctx, DispatchEx *object_prototype, DispatchEx **ret)
330 NumberInstance *number;
333 static const WCHAR NumberW[] = {'N','u','m','b','e','r',0};
335 hres = alloc_number(ctx, object_prototype, &number);
339 V_VT(&number->num) = VT_I4;
340 hres = create_builtin_function(ctx, NumberConstr_value, NumberW, NULL, PROPF_CONSTR, &number->dispex, ret);
342 jsdisp_release(&number->dispex);
346 HRESULT create_number(script_ctx_t *ctx, VARIANT *num, DispatchEx **ret)
348 NumberInstance *number;
351 hres = alloc_number(ctx, NULL, &number);
357 *ret = &number->dispex;