ole32: Remove an unneeded WINAPI and remove some useless comments.
[wine] / dlls / jscript / global.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 "jscript.h"
20 #include "engine.h"
21
22 #include "wine/debug.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
25
26 static const WCHAR NaNW[] = {'N','a','N',0};
27 static const WCHAR InfinityW[] = {'I','n','f','i','n','i','t','y',0};
28 static const WCHAR ArrayW[] = {'A','r','r','a','y',0};
29 static const WCHAR BooleanW[] = {'B','o','o','l','e','a','n',0};
30 static const WCHAR DateW[] = {'D','a','t','e',0};
31 static const WCHAR FunctionW[] = {'F','u','n','c','t','i','o','n',0};
32 static const WCHAR NumberW[] = {'N','u','m','b','e','r',0};
33 static const WCHAR ObjectW[] = {'O','b','j','e','c','t',0};
34 static const WCHAR StringW[] = {'S','t','r','i','n','g',0};
35 static const WCHAR RegExpW[] = {'R','e','g','E','x','p',0};
36 static const WCHAR ActiveXObjectW[] = {'A','c','t','i','v','e','X','O','b','j','e','c','t',0};
37 static const WCHAR VBArrayW[] = {'V','B','A','r','r','a','y',0};
38 static const WCHAR EnumeratorW[] = {'E','n','u','m','e','r','a','t','o','r',0};
39 static const WCHAR escapeW[] = {'e','s','c','a','p','e',0};
40 static const WCHAR evalW[] = {'e','v','a','l',0};
41 static const WCHAR isNaNW[] = {'i','s','N','a','N',0};
42 static const WCHAR isFiniteW[] = {'i','s','F','i','n','i','t','e',0};
43 static const WCHAR parseIntW[] = {'p','a','r','s','e','I','n','t',0};
44 static const WCHAR parseFloatW[] = {'p','a','r','s','e','F','l','o','a','t',0};
45 static const WCHAR unescapeW[] = {'u','n','e','s','c','a','p','e',0};
46 static const WCHAR GetObjectW[] = {'G','e','t','O','b','j','e','c','t',0};
47 static const WCHAR ScriptEngineW[] = {'S','c','r','i','p','t','E','n','g','i','n','e',0};
48 static const WCHAR ScriptEngineMajorVersionW[] =
49     {'S','c','r','i','p','t','E','n','g','i','n','e','M','a','j','o','r','V','e','r','s','i','o','n',0};
50 static const WCHAR ScriptEngineMinorVersionW[] =
51     {'S','c','r','i','p','t','E','n','g','i','n','e','M','i','n','o','r','V','e','r','s','i','o','n',0};
52 static const WCHAR ScriptEngineBuildVersionW[] =
53     {'S','c','r','i','p','t','E','n','g','i','n','e','B','u','i','l','d','V','e','r','s','i','o','n',0};
54 static const WCHAR CollectGarbageW[] = {'C','o','l','l','e','c','t','G','a','r','b','a','g','e',0};
55 static const WCHAR MathW[] = {'M','a','t','h',0};
56
57 static HRESULT constructor_call(DispatchEx *constr, LCID lcid, WORD flags, DISPPARAMS *dp,
58         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
59 {
60     if(flags != DISPATCH_PROPERTYGET)
61         return jsdisp_call_value(constr, lcid, flags, dp, retv, ei, sp);
62
63     V_VT(retv) = VT_DISPATCH;
64     V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(constr);
65     IDispatchEx_AddRef(_IDispatchEx_(constr));
66     return S_OK;
67 }
68
69 static HRESULT JSGlobal_NaN(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
70         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
71 {
72     FIXME("\n");
73     return E_NOTIMPL;
74 }
75
76 static HRESULT JSGlobal_Infinity(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
77         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
78 {
79     FIXME("\n");
80     return E_NOTIMPL;
81 }
82
83 static HRESULT JSGlobal_Array(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
84         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
85 {
86     TRACE("\n");
87
88     return constructor_call(dispex->ctx->array_constr, lcid, flags, dp, retv, ei, sp);
89 }
90
91 static HRESULT JSGlobal_Boolean(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
92         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
93 {
94     TRACE("\n");
95
96     return constructor_call(dispex->ctx->bool_constr, lcid, flags, dp, retv, ei, sp);
97 }
98
99 static HRESULT JSGlobal_Date(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
100         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
101 {
102     TRACE("\n");
103
104     return constructor_call(dispex->ctx->date_constr, lcid, flags, dp, retv, ei, sp);
105 }
106
107 static HRESULT JSGlobal_Function(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
108         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
109 {
110     TRACE("\n");
111
112     return constructor_call(dispex->ctx->function_constr, lcid, flags, dp, retv, ei, sp);
113 }
114
115 static HRESULT JSGlobal_Number(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
116         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
117 {
118     TRACE("\n");
119
120     return constructor_call(dispex->ctx->number_constr, lcid, flags, dp, retv, ei, sp);
121 }
122
123 static HRESULT JSGlobal_Object(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
124         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
125 {
126     TRACE("\n");
127
128     return constructor_call(dispex->ctx->object_constr, lcid, flags, dp, retv, ei, sp);
129 }
130
131 static HRESULT JSGlobal_String(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
132         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
133 {
134     TRACE("\n");
135
136     return constructor_call(dispex->ctx->string_constr, lcid, flags, dp, retv, ei, sp);
137 }
138
139 static HRESULT JSGlobal_RegExp(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
140         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
141 {
142     TRACE("\n");
143
144     return constructor_call(dispex->ctx->regexp_constr, lcid, flags, dp, retv, ei, sp);
145 }
146
147 static HRESULT JSGlobal_ActiveXObject(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
148         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
149 {
150     FIXME("\n");
151     return E_NOTIMPL;
152 }
153
154 static HRESULT JSGlobal_VBArray(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
155         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
156 {
157     FIXME("\n");
158     return E_NOTIMPL;
159 }
160
161 static HRESULT JSGlobal_Enumerator(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
162         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
163 {
164     FIXME("\n");
165     return E_NOTIMPL;
166 }
167
168 static HRESULT JSGlobal_escape(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
169         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
170 {
171     FIXME("\n");
172     return E_NOTIMPL;
173 }
174
175 /* ECMA-262 3rd Edition    15.1.2.1 */
176 static HRESULT JSGlobal_eval(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
177         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
178 {
179     parser_ctx_t *parser_ctx;
180     VARIANT *arg;
181     HRESULT hres;
182
183     TRACE("\n");
184
185     if(!arg_cnt(dp)) {
186         if(retv)
187             V_VT(retv) = VT_EMPTY;
188         return S_OK;
189     }
190
191     arg = get_arg(dp, 0);
192     if(V_VT(arg) != VT_BSTR) {
193         if(retv) {
194             V_VT(retv) = VT_EMPTY;
195             return VariantCopy(retv, arg);
196         }
197         return S_OK;
198     }
199
200     if(!dispex->ctx->exec_ctx) {
201         FIXME("No active exec_ctx\n");
202         return E_UNEXPECTED;
203     }
204
205     TRACE("parsing %s\n", debugstr_w(V_BSTR(arg)));
206     hres = script_parse(dispex->ctx, V_BSTR(arg), &parser_ctx);
207     if(FAILED(hres)) {
208         FIXME("parse failed: %08x\n", hres);
209         return hres;
210     }
211
212     hres = exec_source(dispex->ctx->exec_ctx, parser_ctx, parser_ctx->source, ei, retv);
213     parser_release(parser_ctx);
214
215     return hres;
216 }
217
218 static HRESULT JSGlobal_isNaN(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
219         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
220 {
221     FIXME("\n");
222     return E_NOTIMPL;
223 }
224
225 static HRESULT JSGlobal_isFinite(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
226         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
227 {
228     FIXME("\n");
229     return E_NOTIMPL;
230 }
231
232 static INT char_to_int(WCHAR c)
233 {
234     if('0' <= c && c <= '9')
235         return c - '0';
236     if('a' <= c && c <= 'z')
237         return c - 'a' + 10;
238     if('A' <= c && c <= 'Z')
239         return c - 'A' + 10;
240     return 100;
241 }
242
243 static HRESULT JSGlobal_parseInt(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
244         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
245 {
246     DOUBLE ret = 0.0;
247     INT radix=10, i;
248     WCHAR *ptr;
249     BOOL neg = FALSE;
250     BSTR str;
251     HRESULT hres;
252
253     if(!arg_cnt(dp)) {
254         FIXME("NAN\n");
255         return E_NOTIMPL;
256     }
257
258     if(arg_cnt(dp) >= 2) {
259         hres = to_int32(dispex->ctx, get_arg(dp, 1), ei, &radix);
260         if(FAILED(hres))
261             return hres;
262
263         if(!radix) {
264             radix = 10;
265         }else if(radix < 2 || radix > 36) {
266             WARN("radix %d out of range\n", radix);
267             return E_FAIL;
268         }
269     }
270
271     hres = to_string(dispex->ctx, get_arg(dp, 0), ei, &str);
272     if(FAILED(hres))
273         return hres;
274
275     for(ptr = str; isspaceW(*ptr); ptr++);
276
277     switch(*ptr) {
278     case '+':
279         ptr++;
280         break;
281     case '-':
282         neg = TRUE;
283         ptr++;
284         break;
285     case '0':
286         ptr++;
287         if(*ptr == 'x' || *ptr == 'X') {
288             radix = 16;
289             ptr++;
290         }
291     }
292
293     while(*ptr) {
294         i = char_to_int(*ptr++);
295         if(i > radix)
296             break;
297
298         ret = ret*radix + i;
299     }
300
301     SysFreeString(str);
302
303     if(neg)
304         ret = -ret;
305
306     if(retv)
307         num_set_val(retv, ret);
308     return S_OK;
309 }
310
311 static HRESULT JSGlobal_parseFloat(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
312         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
313 {
314     FIXME("\n");
315     return E_NOTIMPL;
316 }
317
318 static HRESULT JSGlobal_unescape(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
319         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
320 {
321     FIXME("\n");
322     return E_NOTIMPL;
323 }
324
325 static HRESULT JSGlobal_GetObject(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
326         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
327 {
328     FIXME("\n");
329     return E_NOTIMPL;
330 }
331
332 static HRESULT JSGlobal_ScriptEngine(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
333         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
334 {
335     FIXME("\n");
336     return E_NOTIMPL;
337 }
338
339 static HRESULT JSGlobal_ScriptEngineMajorVersion(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
340         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
341 {
342     FIXME("\n");
343     return E_NOTIMPL;
344 }
345
346 static HRESULT JSGlobal_ScriptEngineMinorVersion(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
347         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
348 {
349     FIXME("\n");
350     return E_NOTIMPL;
351 }
352
353 static HRESULT JSGlobal_ScriptEngineBuildVersion(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
354         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
355 {
356     FIXME("\n");
357     return E_NOTIMPL;
358 }
359
360 static HRESULT JSGlobal_CollectGarbage(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
361         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
362 {
363     FIXME("\n");
364     return E_NOTIMPL;
365 }
366
367 static const builtin_prop_t JSGlobal_props[] = {
368     {ActiveXObjectW,             JSGlobal_ActiveXObject,             PROPF_METHOD},
369     {ArrayW,                     JSGlobal_Array,                     PROPF_CONSTR},
370     {BooleanW,                   JSGlobal_Boolean,                   PROPF_CONSTR},
371     {CollectGarbageW,            JSGlobal_CollectGarbage,            PROPF_METHOD},
372     {DateW,                      JSGlobal_Date,                      PROPF_CONSTR},
373     {EnumeratorW,                JSGlobal_Enumerator,                PROPF_METHOD},
374     {FunctionW,                  JSGlobal_Function,                  PROPF_CONSTR},
375     {GetObjectW,                 JSGlobal_GetObject,                 PROPF_METHOD},
376     {InfinityW,                  JSGlobal_Infinity,                  0},
377 /*  {MathW,                      JSGlobal_Math,                      0},  */
378     {NaNW,                       JSGlobal_NaN,                       0},
379     {NumberW,                    JSGlobal_Number,                    PROPF_CONSTR},
380     {ObjectW,                    JSGlobal_Object,                    PROPF_CONSTR},
381     {RegExpW,                    JSGlobal_RegExp,                    PROPF_CONSTR},
382     {ScriptEngineW,              JSGlobal_ScriptEngine,              PROPF_METHOD},
383     {ScriptEngineBuildVersionW,  JSGlobal_ScriptEngineBuildVersion,  PROPF_METHOD},
384     {ScriptEngineMajorVersionW,  JSGlobal_ScriptEngineMajorVersion,  PROPF_METHOD},
385     {ScriptEngineMinorVersionW,  JSGlobal_ScriptEngineMinorVersion,  PROPF_METHOD},
386     {StringW,                    JSGlobal_String,                    PROPF_CONSTR},
387     {VBArrayW,                   JSGlobal_VBArray,                   PROPF_METHOD},
388     {escapeW,                    JSGlobal_escape,                    PROPF_METHOD},
389     {evalW,                      JSGlobal_eval,                      PROPF_METHOD|1},
390     {isFiniteW,                  JSGlobal_isFinite,                  PROPF_METHOD},
391     {isNaNW,                     JSGlobal_isNaN,                     PROPF_METHOD},
392     {parseFloatW,                JSGlobal_parseFloat,                PROPF_METHOD},
393     {parseIntW,                  JSGlobal_parseInt,                  PROPF_METHOD|2},
394     {unescapeW,                  JSGlobal_unescape,                  PROPF_METHOD}
395 };
396
397 static const builtin_info_t JSGlobal_info = {
398     JSCLASS_GLOBAL,
399     {NULL, NULL, 0},
400     sizeof(JSGlobal_props)/sizeof(*JSGlobal_props),
401     JSGlobal_props,
402     NULL,
403     NULL
404 };
405
406 static HRESULT init_constructors(script_ctx_t *ctx)
407 {
408     HRESULT hres;
409
410     hres = init_function_constr(ctx);
411     if(FAILED(hres))
412         return hres;
413
414     hres = create_array_constr(ctx, &ctx->array_constr);
415     if(FAILED(hres))
416         return hres;
417
418     hres = create_bool_constr(ctx, &ctx->bool_constr);
419     if(FAILED(hres))
420         return hres;
421
422     hres = create_date_constr(ctx, &ctx->date_constr);
423     if(FAILED(hres))
424         return hres;
425
426     hres = create_number_constr(ctx, &ctx->number_constr);
427     if(FAILED(hres))
428         return hres;
429
430     hres = create_object_constr(ctx, &ctx->object_constr);
431     if(FAILED(hres))
432         return hres;
433
434     hres = create_regexp_constr(ctx, &ctx->regexp_constr);
435     if(FAILED(hres))
436         return hres;
437
438     hres = create_string_constr(ctx, &ctx->string_constr);
439     if(FAILED(hres))
440         return hres;
441
442     return S_OK;
443 }
444
445 HRESULT init_global(script_ctx_t *ctx)
446 {
447     DispatchEx *math;
448     VARIANT var;
449     HRESULT hres;
450
451     if(ctx->global)
452         return S_OK;
453
454     hres = init_constructors(ctx);
455     if(FAILED(hres))
456         return hres;
457
458     hres = create_dispex(ctx, &JSGlobal_info, NULL, &ctx->global);
459     if(FAILED(hres))
460         return hres;
461
462     hres = create_math(ctx, &math);
463     if(FAILED(hres))
464         return hres;
465
466     V_VT(&var) = VT_DISPATCH;
467     V_DISPATCH(&var) = (IDispatch*)_IDispatchEx_(math);
468     hres = jsdisp_propput_name(ctx->global, MathW, ctx->lcid, &var, NULL/*FIXME*/, NULL/*FIXME*/);
469     jsdisp_release(math);
470
471     return hres;
472 }