jscript: Added String.match implementation for non-regexp arguments.
[wine] / dlls / jscript / jsutils.c
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include <math.h>
20
21 #include "jscript.h"
22 #include "engine.h"
23
24 #include "wine/debug.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
27
28 const char *debugstr_variant(const VARIANT *v)
29 {
30     switch(V_VT(v)) {
31     case VT_EMPTY:
32         return wine_dbg_sprintf("{VT_EMPTY}");
33     case VT_NULL:
34         return wine_dbg_sprintf("{VT_NULL}");
35     case VT_I4:
36         return wine_dbg_sprintf("{VT_I4: %d}", V_I4(v));
37     case VT_R8:
38         return wine_dbg_sprintf("{VT_R8: %lf}", V_R8(v));
39     case VT_BSTR:
40         return wine_dbg_sprintf("{VT_BSTR: %s}", debugstr_w(V_BSTR(v)));
41     case VT_DISPATCH:
42         return wine_dbg_sprintf("{VT_DISPATCH: %p}", V_DISPATCH(v));
43     case VT_BOOL:
44         return wine_dbg_sprintf("{VT_BOOL: %x}", V_BOOL(v));
45     default:
46         return wine_dbg_sprintf("{vt %d}", V_VT(v));
47     }
48 }
49
50 #define MIN_BLOCK_SIZE  128
51
52 static inline DWORD block_size(DWORD block)
53 {
54     return MIN_BLOCK_SIZE << block;
55 }
56
57 void jsheap_init(jsheap_t *heap)
58 {
59     memset(heap, 0, sizeof(*heap));
60     list_init(&heap->custom_blocks);
61 }
62
63 void *jsheap_alloc(jsheap_t *heap, DWORD size)
64 {
65     struct list *list;
66     void *tmp;
67
68     if(!heap->block_cnt) {
69         if(!heap->blocks) {
70             heap->blocks = heap_alloc(sizeof(void*));
71             if(!heap->blocks)
72                 return NULL;
73         }
74
75         tmp = heap_alloc(block_size(0));
76         if(!tmp)
77             return NULL;
78
79         heap->blocks[0] = tmp;
80         heap->block_cnt = 1;
81     }
82
83     if(heap->offset + size < block_size(heap->last_block)) {
84         tmp = ((BYTE*)heap->blocks[heap->last_block])+heap->offset;
85         heap->offset += size;
86         return tmp;
87     }
88
89     if(size < block_size(heap->last_block+1)) {
90         if(heap->last_block+1 == heap->block_cnt) {
91             tmp = heap_realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*));
92             if(!tmp)
93                 return NULL;
94             heap->blocks = tmp;
95         }
96
97         tmp = heap_alloc(block_size(heap->block_cnt+1));
98         if(!tmp)
99             return NULL;
100
101         heap->blocks[heap->block_cnt++] = tmp;
102
103         heap->last_block++;
104         heap->offset = size;
105         return heap->blocks[heap->last_block];
106     }
107
108     list = heap_alloc(size + sizeof(struct list));
109     if(!list)
110         return NULL;
111
112     list_add_head(&heap->custom_blocks, list);
113     return list+1;
114 }
115
116 void *jsheap_grow(jsheap_t *heap, void *mem, DWORD size, DWORD inc)
117 {
118     if(mem == (BYTE*)heap->blocks[heap->last_block] + heap->offset-size
119        && heap->offset+inc < block_size(heap->last_block)) {
120         heap->offset += inc;
121         return mem;
122     }
123
124     return jsheap_alloc(heap, size+inc);
125 }
126
127 void jsheap_clear(jsheap_t *heap)
128 {
129     struct list *tmp;
130
131     if(!heap)
132         return;
133
134     while((tmp = list_next(&heap->custom_blocks, &heap->custom_blocks))) {
135         list_remove(tmp);
136         heap_free(tmp);
137     }
138
139     heap->last_block = heap->offset = 0;
140 }
141
142 void jsheap_free(jsheap_t *heap)
143 {
144     DWORD i;
145
146     jsheap_clear(heap);
147
148     for(i=0; i < heap->block_cnt; i++)
149         heap_free(heap->blocks[i]);
150     heap_free(heap->blocks);
151
152     jsheap_init(heap);
153 }
154
155 jsheap_t *jsheap_mark(jsheap_t *heap)
156 {
157     if(heap->mark)
158         return NULL;
159
160     heap->mark = TRUE;
161     return heap;
162 }
163
164 /* ECMA-262 3rd Edition    9.1 */
165 HRESULT to_primitive(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
166 {
167     switch(V_VT(v)) {
168     case VT_EMPTY:
169     case VT_NULL:
170     case VT_BOOL:
171     case VT_I4:
172     case VT_R8:
173         *ret = *v;
174         break;
175     case VT_BSTR:
176         V_VT(ret) = VT_BSTR;
177         V_BSTR(ret) = SysAllocString(V_BSTR(v));
178         break;
179     case VT_DISPATCH:
180         return disp_propget(V_DISPATCH(v), DISPID_VALUE, ctx->lcid, ret, ei, NULL /*FIXME*/);
181     default:
182         FIXME("Unimplemented for vt %d\n", V_VT(v));
183         return E_NOTIMPL;
184     }
185
186     return S_OK;
187 }
188
189 /* ECMA-262 3rd Edition    9.2 */
190 HRESULT to_boolean(VARIANT *v, VARIANT_BOOL *b)
191 {
192     switch(V_VT(v)) {
193     case VT_EMPTY:
194     case VT_NULL:
195         *b = VARIANT_FALSE;
196         break;
197     case VT_I4:
198         *b = V_I4(v) ? VARIANT_TRUE : VARIANT_FALSE;
199         break;
200     case VT_R8:
201         *b = V_R8(v) ? VARIANT_TRUE : VARIANT_FALSE;
202         break;
203     case VT_BSTR:
204         *b = V_BSTR(v) && *V_BSTR(v) ? VARIANT_TRUE : VARIANT_FALSE;
205         break;
206     case VT_DISPATCH:
207         *b = V_DISPATCH(v) ? VARIANT_TRUE : VARIANT_FALSE;
208         break;
209     case VT_BOOL:
210         *b = V_BOOL(v);
211         break;
212     default:
213         FIXME("unimplemented for vt %d\n", V_VT(v));
214         return E_NOTIMPL;
215     }
216
217     return S_OK;
218 }
219
220 static int hex_to_int(WCHAR c)
221 {
222     if('0' <= c && c <= '9')
223         return c-'0';
224
225     if('a' <= c && c <= 'f')
226         return c-'a'+10;
227
228     if('A' <= c && c <= 'F')
229         return c-'A'+10;
230
231     return -1;
232 }
233
234 /* ECMA-262 3rd Edition    9.3.1 */
235 static HRESULT str_to_number(BSTR str, VARIANT *ret)
236 {
237     const WCHAR *ptr = str;
238     BOOL neg = FALSE;
239     DOUBLE d = 0.0;
240
241     static const WCHAR infinityW[] = {'I','n','f','i','n','i','t','y'};
242
243     while(isspaceW(*ptr))
244         ptr++;
245
246     if(!strncmpW(ptr, infinityW, sizeof(infinityW)/sizeof(WCHAR))) {
247         ptr += sizeof(infinityW)/sizeof(WCHAR);
248         while(*ptr && isspaceW(*ptr))
249             ptr++;
250
251         if(*ptr) {
252             FIXME("NaN\n");
253             return E_NOTIMPL;
254         }
255
256         FIXME("inf\n");
257         return E_NOTIMPL;
258     }
259
260     if(*ptr == '-') {
261         neg = TRUE;
262         ptr++;
263     }else if(*ptr == '+') {
264         ptr++;
265     }else if(*ptr == '0' && ptr[1] == 'x') {
266         DWORD l = 0;
267
268         ptr += 2;
269         while((l = hex_to_int(*ptr)) != -1) {
270             d = d*16 + l;
271             ptr++;
272         }
273
274         num_set_val(ret, d);
275         return S_OK;
276     }
277
278     while(isdigitW(*ptr))
279         d = d*10 + (*ptr++ - '0');
280
281     if(*ptr == 'e' || *ptr == 'E') {
282         BOOL eneg = FALSE;
283         LONG l = 0;
284
285         ptr++;
286         if(*ptr == '-') {
287             ptr++;
288             eneg = TRUE;
289         }else if(*ptr == '+') {
290             ptr++;
291         }
292
293         while(isdigitW(*ptr))
294             l = l*10 + (*ptr++ - '0');
295         if(eneg)
296             l = -l;
297
298         d *= pow(10, l);
299     }else if(*ptr == '.') {
300         DOUBLE dec = 0.1;
301
302         ptr++;
303         while(isdigitW(*ptr)) {
304             d += dec * (*ptr++ - '0');
305             dec *= 0.1;
306         }
307     }
308
309     while(isspaceW(*ptr))
310         ptr++;
311
312     if(*ptr) {
313         FIXME("NaN\n");
314         return E_NOTIMPL;
315     }
316
317     if(neg)
318         d = -d;
319
320     num_set_val(ret, d);
321     return S_OK;
322 }
323
324 /* ECMA-262 3rd Edition    9.3 */
325 HRESULT to_number(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
326 {
327     switch(V_VT(v)) {
328     case VT_NULL:
329         V_VT(ret) = VT_I4;
330         V_I4(ret) = 0;
331         break;
332     case VT_I4:
333     case VT_R8:
334         *ret = *v;
335         break;
336     case VT_BSTR:
337         return str_to_number(V_BSTR(v), ret);
338     case VT_DISPATCH: {
339         VARIANT prim;
340         HRESULT hres;
341
342         hres = to_primitive(ctx, v, ei, &prim);
343         if(FAILED(hres))
344             return hres;
345
346         hres = to_number(ctx, &prim, ei, ret);
347         VariantClear(&prim);
348         return hres;
349     }
350     case VT_BOOL:
351         V_VT(ret) = VT_I4;
352         V_I4(ret) = V_BOOL(v) ? 1 : 0;
353         break;
354     default:
355         FIXME("unimplemented for vt %d\n", V_VT(v));
356         return E_NOTIMPL;
357     }
358
359     return S_OK;
360 }
361
362 /* ECMA-262 3rd Edition    9.4 */
363 HRESULT to_integer(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
364 {
365     VARIANT num;
366     HRESULT hres;
367
368     hres = to_number(ctx, v, ei, &num);
369     if(FAILED(hres))
370         return hres;
371
372     if(V_VT(&num) == VT_I4)
373         *ret = num;
374     else
375         num_set_val(ret, V_R8(&num) >= 0.0 ? floor(V_R8(&num)) : -floor(-V_R8(&num)));
376
377     return S_OK;
378 }
379
380 /* ECMA-262 3rd Edition    9.5 */
381 HRESULT to_int32(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, INT *ret)
382 {
383     VARIANT num;
384     HRESULT hres;
385
386     hres = to_number(ctx, v, ei, &num);
387     if(FAILED(hres))
388         return hres;
389
390     *ret = V_VT(&num) == VT_I4 ? V_I4(&num) : (INT)V_R8(&num);
391     return S_OK;
392 }
393
394 /* ECMA-262 3rd Edition    9.6 */
395 HRESULT to_uint32(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, DWORD *ret)
396 {
397     VARIANT num;
398     HRESULT hres;
399
400     hres = to_number(ctx, v, ei, &num);
401     if(FAILED(hres))
402         return hres;
403
404     *ret = V_VT(&num) == VT_I4 ? V_I4(&num) : (DWORD)V_R8(&num);
405     return S_OK;
406 }
407
408 static BSTR int_to_bstr(INT i)
409 {
410     WCHAR buf[12], *p;
411     BOOL neg = FALSE;
412
413     if(!i) {
414         static const WCHAR zeroW[] = {'0',0};
415         return SysAllocString(zeroW);
416     }
417
418     if(i < 0) {
419         neg = TRUE;
420         i = -i;
421     }
422
423     p = buf + sizeof(buf)/sizeof(*buf)-1;
424     *p-- = 0;
425     while(i) {
426         *p-- = i%10 + '0';
427         i /= 10;
428     }
429
430     if(neg)
431         *p = '-';
432     else
433         p++;
434
435     return SysAllocString(p);
436 }
437
438 /* ECMA-262 3rd Edition    9.8 */
439 HRESULT to_string(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, BSTR *str)
440 {
441     const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
442     const WCHAR nullW[] = {'n','u','l','l',0};
443     const WCHAR trueW[] = {'t','r','u','e',0};
444     const WCHAR falseW[] = {'f','a','l','s','e',0};
445
446     switch(V_VT(v)) {
447     case VT_EMPTY:
448         *str = SysAllocString(undefinedW);
449         break;
450     case VT_NULL:
451         *str = SysAllocString(nullW);
452         break;
453     case VT_I4:
454         *str = int_to_bstr(V_I4(v));
455         break;
456     case VT_R8: {
457         VARIANT strv;
458         HRESULT hres;
459
460         V_VT(&strv) = VT_EMPTY;
461         hres = VariantChangeType(&strv, v, 0, VT_BSTR);
462         if(FAILED(hres))
463             return hres;
464
465         *str = V_BSTR(&strv);
466         return S_OK;
467     }
468     case VT_BSTR:
469         *str = SysAllocString(V_BSTR(v));
470         break;
471     case VT_DISPATCH: {
472         VARIANT prim;
473         HRESULT hres;
474
475         hres = to_primitive(ctx, v, ei, &prim);
476         if(FAILED(hres))
477             return hres;
478
479         hres = to_string(ctx, &prim, ei, str);
480         VariantClear(&prim);
481         return hres;
482     }
483     case VT_BOOL:
484         *str = SysAllocString(V_BOOL(v) ? trueW : falseW);
485         break;
486     default:
487         FIXME("unsupported vt %d\n", V_VT(v));
488         return E_NOTIMPL;
489     }
490
491     return *str ? S_OK : E_OUTOFMEMORY;
492 }
493
494 /* ECMA-262 3rd Edition    9.9 */
495 HRESULT to_object(exec_ctx_t *ctx, VARIANT *v, IDispatch **disp)
496 {
497     DispatchEx *dispex;
498     HRESULT hres;
499
500     switch(V_VT(v)) {
501     case VT_BSTR:
502         hres = create_string(ctx->parser->script, V_BSTR(v), SysStringLen(V_BSTR(v)), &dispex);
503         if(FAILED(hres))
504             return hres;
505
506         *disp = (IDispatch*)_IDispatchEx_(dispex);
507         break;
508     case VT_I4:
509     case VT_R8:
510         hres = create_number(ctx->parser->script, v, &dispex);
511         if(FAILED(hres))
512             return hres;
513
514         *disp = (IDispatch*)_IDispatchEx_(dispex);
515         break;
516     case VT_DISPATCH:
517         IDispatch_AddRef(V_DISPATCH(v));
518         *disp = V_DISPATCH(v);
519         break;
520     case VT_BOOL:
521         hres = create_bool(ctx->parser->script, V_BOOL(v), &dispex);
522         if(FAILED(hres))
523             return hres;
524
525         *disp = (IDispatch*)_IDispatchEx_(dispex);
526         break;
527     default:
528         FIXME("unsupported vt %d\n", V_VT(v));
529         return E_NOTIMPL;
530     }
531
532     return S_OK;
533 }