shdoclc: Add English neutral translations and fix US English.
[wine/hacks.git] / dlls / jscript / jsutils.c
blobeab850bfe3def3f8ab3e1f26f9faab0e43143538
1 /*
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
19 #include "config.h"
20 #include "wine/port.h"
22 #include <math.h>
24 #include "jscript.h"
25 #include "engine.h"
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
30 WINE_DECLARE_DEBUG_CHANNEL(heap);
32 const char *debugstr_variant(const VARIANT *v)
34 switch(V_VT(v)) {
35 case VT_EMPTY:
36 return wine_dbg_sprintf("{VT_EMPTY}");
37 case VT_NULL:
38 return wine_dbg_sprintf("{VT_NULL}");
39 case VT_I4:
40 return wine_dbg_sprintf("{VT_I4: %d}", V_I4(v));
41 case VT_R8:
42 return wine_dbg_sprintf("{VT_R8: %lf}", V_R8(v));
43 case VT_BSTR:
44 return wine_dbg_sprintf("{VT_BSTR: %s}", debugstr_w(V_BSTR(v)));
45 case VT_DISPATCH:
46 return wine_dbg_sprintf("{VT_DISPATCH: %p}", V_DISPATCH(v));
47 case VT_BOOL:
48 return wine_dbg_sprintf("{VT_BOOL: %x}", V_BOOL(v));
49 default:
50 return wine_dbg_sprintf("{vt %d}", V_VT(v));
54 #define MIN_BLOCK_SIZE 128
55 #define ARENA_FREE_FILLER 0xaa
57 static inline DWORD block_size(DWORD block)
59 return MIN_BLOCK_SIZE << block;
62 void jsheap_init(jsheap_t *heap)
64 memset(heap, 0, sizeof(*heap));
65 list_init(&heap->custom_blocks);
68 void *jsheap_alloc(jsheap_t *heap, DWORD size)
70 struct list *list;
71 void *tmp;
73 if(!heap->block_cnt) {
74 if(!heap->blocks) {
75 heap->blocks = heap_alloc(sizeof(void*));
76 if(!heap->blocks)
77 return NULL;
80 tmp = heap_alloc(block_size(0));
81 if(!tmp)
82 return NULL;
84 heap->blocks[0] = tmp;
85 heap->block_cnt = 1;
88 if(heap->offset + size <= block_size(heap->last_block)) {
89 tmp = ((BYTE*)heap->blocks[heap->last_block])+heap->offset;
90 heap->offset += size;
91 return tmp;
94 if(size <= block_size(heap->last_block+1)) {
95 if(heap->last_block+1 == heap->block_cnt) {
96 tmp = heap_realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*));
97 if(!tmp)
98 return NULL;
100 heap->blocks = tmp;
101 heap->blocks[heap->block_cnt] = heap_alloc(block_size(heap->block_cnt));
102 if(!heap->blocks[heap->block_cnt])
103 return NULL;
105 heap->block_cnt++;
108 heap->last_block++;
109 heap->offset = size;
110 return heap->blocks[heap->last_block];
113 list = heap_alloc(size + sizeof(struct list));
114 if(!list)
115 return NULL;
117 list_add_head(&heap->custom_blocks, list);
118 return list+1;
121 void *jsheap_grow(jsheap_t *heap, void *mem, DWORD size, DWORD inc)
123 if(mem == (BYTE*)heap->blocks[heap->last_block] + heap->offset-size
124 && heap->offset+inc < block_size(heap->last_block)) {
125 heap->offset += inc;
126 return mem;
129 return jsheap_alloc(heap, size+inc);
132 void jsheap_clear(jsheap_t *heap)
134 struct list *tmp;
136 if(!heap)
137 return;
139 while((tmp = list_next(&heap->custom_blocks, &heap->custom_blocks))) {
140 list_remove(tmp);
141 heap_free(tmp);
144 if(WARN_ON(heap)) {
145 DWORD i;
147 for(i=0; i < heap->block_cnt; i++)
148 memset(heap->blocks[i], ARENA_FREE_FILLER, block_size(i));
151 heap->last_block = heap->offset = 0;
152 heap->mark = FALSE;
155 void jsheap_free(jsheap_t *heap)
157 DWORD i;
159 jsheap_clear(heap);
161 for(i=0; i < heap->block_cnt; i++)
162 heap_free(heap->blocks[i]);
163 heap_free(heap->blocks);
165 jsheap_init(heap);
168 jsheap_t *jsheap_mark(jsheap_t *heap)
170 if(heap->mark)
171 return NULL;
173 heap->mark = TRUE;
174 return heap;
177 /* ECMA-262 3rd Edition 9.1 */
178 HRESULT to_primitive(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
180 switch(V_VT(v)) {
181 case VT_EMPTY:
182 case VT_NULL:
183 case VT_BOOL:
184 case VT_I4:
185 case VT_R8:
186 *ret = *v;
187 break;
188 case VT_BSTR:
189 V_VT(ret) = VT_BSTR;
190 V_BSTR(ret) = SysAllocString(V_BSTR(v));
191 break;
192 case VT_DISPATCH:
193 return disp_propget(V_DISPATCH(v), DISPID_VALUE, ctx->lcid, ret, ei, NULL /*FIXME*/);
194 default:
195 FIXME("Unimplemented for vt %d\n", V_VT(v));
196 return E_NOTIMPL;
199 return S_OK;
202 /* ECMA-262 3rd Edition 9.2 */
203 HRESULT to_boolean(VARIANT *v, VARIANT_BOOL *b)
205 switch(V_VT(v)) {
206 case VT_EMPTY:
207 case VT_NULL:
208 *b = VARIANT_FALSE;
209 break;
210 case VT_I4:
211 *b = V_I4(v) ? VARIANT_TRUE : VARIANT_FALSE;
212 break;
213 case VT_R8:
214 if(isnan(V_R8(v))) *b = VARIANT_FALSE;
215 else *b = V_R8(v) ? VARIANT_TRUE : VARIANT_FALSE;
216 break;
217 case VT_BSTR:
218 *b = V_BSTR(v) && *V_BSTR(v) ? VARIANT_TRUE : VARIANT_FALSE;
219 break;
220 case VT_DISPATCH:
221 *b = V_DISPATCH(v) ? VARIANT_TRUE : VARIANT_FALSE;
222 break;
223 case VT_BOOL:
224 *b = V_BOOL(v);
225 break;
226 default:
227 FIXME("unimplemented for vt %d\n", V_VT(v));
228 return E_NOTIMPL;
231 return S_OK;
234 static int hex_to_int(WCHAR c)
236 if('0' <= c && c <= '9')
237 return c-'0';
239 if('a' <= c && c <= 'f')
240 return c-'a'+10;
242 if('A' <= c && c <= 'F')
243 return c-'A'+10;
245 return -1;
248 /* ECMA-262 3rd Edition 9.3.1 */
249 static HRESULT str_to_number(BSTR str, VARIANT *ret)
251 const WCHAR *ptr = str;
252 BOOL neg = FALSE;
253 DOUBLE d = 0.0;
255 static const WCHAR infinityW[] = {'I','n','f','i','n','i','t','y'};
257 while(isspaceW(*ptr))
258 ptr++;
260 if(*ptr == '-') {
261 neg = TRUE;
262 ptr++;
263 }else if(*ptr == '+') {
264 ptr++;
267 if(!strncmpW(ptr, infinityW, sizeof(infinityW)/sizeof(WCHAR))) {
268 ptr += sizeof(infinityW)/sizeof(WCHAR);
269 while(*ptr && isspaceW(*ptr))
270 ptr++;
272 if(*ptr)
273 num_set_nan(ret);
274 else
275 num_set_inf(ret, !neg);
276 return S_OK;
279 if(*ptr == '0' && ptr[1] == 'x') {
280 DWORD l = 0;
282 ptr += 2;
283 while((l = hex_to_int(*ptr)) != -1) {
284 d = d*16 + l;
285 ptr++;
288 num_set_val(ret, d);
289 return S_OK;
292 while(isdigitW(*ptr))
293 d = d*10 + (*ptr++ - '0');
295 if(*ptr == 'e' || *ptr == 'E') {
296 BOOL eneg = FALSE;
297 LONG l = 0;
299 ptr++;
300 if(*ptr == '-') {
301 ptr++;
302 eneg = TRUE;
303 }else if(*ptr == '+') {
304 ptr++;
307 while(isdigitW(*ptr))
308 l = l*10 + (*ptr++ - '0');
309 if(eneg)
310 l = -l;
312 d *= pow(10, l);
313 }else if(*ptr == '.') {
314 DOUBLE dec = 0.1;
316 ptr++;
317 while(isdigitW(*ptr)) {
318 d += dec * (*ptr++ - '0');
319 dec *= 0.1;
323 while(isspaceW(*ptr))
324 ptr++;
326 if(*ptr) {
327 num_set_nan(ret);
328 return S_OK;
331 if(neg)
332 d = -d;
334 num_set_val(ret, d);
335 return S_OK;
338 /* ECMA-262 3rd Edition 9.3 */
339 HRESULT to_number(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
341 switch(V_VT(v)) {
342 case VT_EMPTY:
343 num_set_nan(ret);
344 break;
345 case VT_NULL:
346 V_VT(ret) = VT_I4;
347 V_I4(ret) = 0;
348 break;
349 case VT_I4:
350 case VT_R8:
351 *ret = *v;
352 break;
353 case VT_BSTR:
354 return str_to_number(V_BSTR(v), ret);
355 case VT_DISPATCH: {
356 VARIANT prim;
357 HRESULT hres;
359 hres = to_primitive(ctx, v, ei, &prim);
360 if(FAILED(hres))
361 return hres;
363 hres = to_number(ctx, &prim, ei, ret);
364 VariantClear(&prim);
365 return hres;
367 case VT_BOOL:
368 V_VT(ret) = VT_I4;
369 V_I4(ret) = V_BOOL(v) ? 1 : 0;
370 break;
371 default:
372 FIXME("unimplemented for vt %d\n", V_VT(v));
373 return E_NOTIMPL;
376 return S_OK;
379 /* ECMA-262 3rd Edition 9.4 */
380 HRESULT to_integer(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
382 VARIANT num;
383 HRESULT hres;
385 hres = to_number(ctx, v, ei, &num);
386 if(FAILED(hres))
387 return hres;
389 if(V_VT(&num) == VT_I4)
390 *ret = num;
391 else
392 num_set_val(ret, V_R8(&num) >= 0.0 ? floor(V_R8(&num)) : -floor(-V_R8(&num)));
394 return S_OK;
397 /* ECMA-262 3rd Edition 9.5 */
398 HRESULT to_int32(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, INT *ret)
400 VARIANT num;
401 HRESULT hres;
403 hres = to_number(ctx, v, ei, &num);
404 if(FAILED(hres))
405 return hres;
407 *ret = V_VT(&num) == VT_I4 ? V_I4(&num) : (INT)V_R8(&num);
408 return S_OK;
411 /* ECMA-262 3rd Edition 9.6 */
412 HRESULT to_uint32(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, DWORD *ret)
414 VARIANT num;
415 HRESULT hres;
417 hres = to_number(ctx, v, ei, &num);
418 if(FAILED(hres))
419 return hres;
421 *ret = V_VT(&num) == VT_I4 ? V_I4(&num) : (DWORD)V_R8(&num);
422 return S_OK;
425 static BSTR int_to_bstr(INT i)
427 WCHAR buf[12], *p;
428 BOOL neg = FALSE;
430 if(!i) {
431 static const WCHAR zeroW[] = {'0',0};
432 return SysAllocString(zeroW);
435 if(i < 0) {
436 neg = TRUE;
437 i = -i;
440 p = buf + sizeof(buf)/sizeof(*buf)-1;
441 *p-- = 0;
442 while(i) {
443 *p-- = i%10 + '0';
444 i /= 10;
447 if(neg)
448 *p = '-';
449 else
450 p++;
452 return SysAllocString(p);
455 /* ECMA-262 3rd Edition 9.8 */
456 HRESULT to_string(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, BSTR *str)
458 const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
459 const WCHAR nullW[] = {'n','u','l','l',0};
460 const WCHAR trueW[] = {'t','r','u','e',0};
461 const WCHAR falseW[] = {'f','a','l','s','e',0};
463 switch(V_VT(v)) {
464 case VT_EMPTY:
465 *str = SysAllocString(undefinedW);
466 break;
467 case VT_NULL:
468 *str = SysAllocString(nullW);
469 break;
470 case VT_I4:
471 *str = int_to_bstr(V_I4(v));
472 break;
473 case VT_R8: {
474 VARIANT strv;
475 HRESULT hres;
477 V_VT(&strv) = VT_EMPTY;
478 hres = VariantChangeTypeEx(&strv, v, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT), 0, VT_BSTR);
479 if(FAILED(hres))
480 return hres;
482 *str = V_BSTR(&strv);
483 return S_OK;
485 case VT_BSTR:
486 *str = SysAllocString(V_BSTR(v));
487 break;
488 case VT_DISPATCH: {
489 VARIANT prim;
490 HRESULT hres;
492 hres = to_primitive(ctx, v, ei, &prim);
493 if(FAILED(hres))
494 return hres;
496 hres = to_string(ctx, &prim, ei, str);
497 VariantClear(&prim);
498 return hres;
500 case VT_BOOL:
501 *str = SysAllocString(V_BOOL(v) ? trueW : falseW);
502 break;
503 default:
504 FIXME("unsupported vt %d\n", V_VT(v));
505 return E_NOTIMPL;
508 return *str ? S_OK : E_OUTOFMEMORY;
511 /* ECMA-262 3rd Edition 9.9 */
512 HRESULT to_object(exec_ctx_t *ctx, VARIANT *v, IDispatch **disp)
514 DispatchEx *dispex;
515 HRESULT hres;
517 switch(V_VT(v)) {
518 case VT_BSTR:
519 hres = create_string(ctx->parser->script, V_BSTR(v), SysStringLen(V_BSTR(v)), &dispex);
520 if(FAILED(hres))
521 return hres;
523 *disp = (IDispatch*)_IDispatchEx_(dispex);
524 break;
525 case VT_I4:
526 case VT_R8:
527 hres = create_number(ctx->parser->script, v, &dispex);
528 if(FAILED(hres))
529 return hres;
531 *disp = (IDispatch*)_IDispatchEx_(dispex);
532 break;
533 case VT_DISPATCH:
534 IDispatch_AddRef(V_DISPATCH(v));
535 *disp = V_DISPATCH(v);
536 break;
537 case VT_BOOL:
538 hres = create_bool(ctx->parser->script, V_BOOL(v), &dispex);
539 if(FAILED(hres))
540 return hres;
542 *disp = (IDispatch*)_IDispatchEx_(dispex);
543 break;
544 default:
545 FIXME("unsupported vt %d\n", V_VT(v));
546 return E_NOTIMPL;
549 return S_OK;