1#include "jsi.h"
2#include "jslex.h"
3#include "jscompile.h"
4#include "jsvalue.h"
5#include "jsbuiltin.h"
6
7static void jsB_globalf(js_State *J, const char *name, js_CFunction cfun, int n)
8{
9 js_newcfunction(J, cfun, name, n);
10 js_defglobal(J, name, JS_DONTENUM);
11}
12
13void jsB_propf(js_State *J, const char *name, js_CFunction cfun, int n)
14{
15 const char *pname = strrchr(name, '.');
16 pname = pname ? pname + 1 : name;
17 js_newcfunction(J, cfun, name, n);
18 js_defproperty(J, -2, pname, JS_DONTENUM);
19}
20
21void jsB_propn(js_State *J, const char *name, double number)
22{
23 js_pushnumber(J, number);
24 js_defproperty(J, -2, name, JS_READONLY | JS_DONTENUM | JS_DONTCONF);
25}
26
27void jsB_props(js_State *J, const char *name, const char *string)
28{
29 js_pushliteral(J, string);
30 js_defproperty(J, -2, name, JS_DONTENUM);
31}
32
33static void jsB_parseInt(js_State *J)
34{
35 const char *s = js_tostring(J, 1);
36 int radix = js_isdefined(J, 2) ? js_tointeger(J, 2) : 10;
37 double sign = 1;
38 double n;
39 char *e;
40
41 while (jsY_iswhite(*s) || jsY_isnewline(*s))
42 ++s;
43 if (*s == '-') {
44 ++s;
45 sign = -1;
46 } else if (*s == '+') {
47 ++s;
48 }
49 if (radix == 0) {
50 radix = 10;
51 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
52 s += 2;
53 radix = 16;
54 }
55 } else if (radix < 2 || radix > 36) {
56 js_pushnumber(J, NAN);
57 return;
58 }
59 n = strtol(s, &e, radix);
60 if (s == e)
61 js_pushnumber(J, NAN);
62 else
63 js_pushnumber(J, n * sign);
64}
65
66static void jsB_parseFloat(js_State *J)
67{
68 const char *s = js_tostring(J, 1);
69 char *e;
70 double n;
71
72 while (jsY_iswhite(*s) || jsY_isnewline(*s)) ++s;
73 if (!strncmp(s, "Infinity", 8))
74 js_pushnumber(J, INFINITY);
75 else if (!strncmp(s, "+Infinity", 9))
76 js_pushnumber(J, INFINITY);
77 else if (!strncmp(s, "-Infinity", 9))
78 js_pushnumber(J, -INFINITY);
79 else {
80 n = js_stringtofloat(s, &e);
81 if (e == s)
82 js_pushnumber(J, NAN);
83 else
84 js_pushnumber(J, n);
85 }
86}
87
88static void jsB_isNaN(js_State *J)
89{
90 double n = js_tonumber(J, 1);
91 js_pushboolean(J, isnan(n));
92}
93
94static void jsB_isFinite(js_State *J)
95{
96 double n = js_tonumber(J, 1);
97 js_pushboolean(J, isfinite(n));
98}
99
100static void Encode(js_State *J, const char *str, const char *unescaped)
101{
102 js_Buffer *sb = NULL;
103
104 static const char *HEX = "0123456789ABCDEF";
105
106 if (js_try(J)) {
107 js_free(J, sb);
108 js_throw(J);
109 }
110
111 while (*str) {
112 int c = (unsigned char) *str++;
113 if (strchr(unescaped, c))
114 js_putc(J, &sb, c);
115 else {
116 js_putc(J, &sb, '%');
117 js_putc(J, &sb, HEX[(c >> 4) & 0xf]);
118 js_putc(J, &sb, HEX[c & 0xf]);
119 }
120 }
121 js_putc(J, &sb, 0);
122
123 js_pushstring(J, sb ? sb->s : "");
124 js_endtry(J);
125 js_free(J, sb);
126}
127
128static void Decode(js_State *J, const char *str, const char *reserved)
129{
130 js_Buffer *sb = NULL;
131 int a, b;
132
133 if (js_try(J)) {
134 js_free(J, sb);
135 js_throw(J);
136 }
137
138 while (*str) {
139 int c = (unsigned char) *str++;
140 if (c != '%')
141 js_putc(J, &sb, c);
142 else {
143 if (!str[0] || !str[1])
144 js_urierror(J, "truncated escape sequence");
145 a = *str++;
146 b = *str++;
147 if (!jsY_ishex(a) || !jsY_ishex(b))
148 js_urierror(J, "invalid escape sequence");
149 c = jsY_tohex(a) << 4 | jsY_tohex(b);
150 if (!strchr(reserved, c))
151 js_putc(J, &sb, c);
152 else {
153 js_putc(J, &sb, '%');
154 js_putc(J, &sb, a);
155 js_putc(J, &sb, b);
156 }
157 }
158 }
159 js_putc(J, &sb, 0);
160
161 js_pushstring(J, sb ? sb->s : "");
162 js_endtry(J);
163 js_free(J, sb);
164}
165
166#define URIRESERVED ";/?:@&=+$,"
167#define URIALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
168#define URIDIGIT "0123456789"
169#define URIMARK "-_.!~*`()"
170#define URIUNESCAPED URIALPHA URIDIGIT URIMARK
171
172static void jsB_decodeURI(js_State *J)
173{
174 Decode(J, js_tostring(J, 1), URIRESERVED "#");
175}
176
177static void jsB_decodeURIComponent(js_State *J)
178{
179 Decode(J, js_tostring(J, 1), "");
180}
181
182static void jsB_encodeURI(js_State *J)
183{
184 Encode(J, js_tostring(J, 1), URIUNESCAPED URIRESERVED "#");
185}
186
187static void jsB_encodeURIComponent(js_State *J)
188{
189 Encode(J, js_tostring(J, 1), URIUNESCAPED);
190}
191
192void jsB_init(js_State *J)
193{
194 /* Create the prototype objects here, before the constructors */
195 J->Object_prototype = jsV_newobject(J, JS_COBJECT, NULL);
196 J->Array_prototype = jsV_newobject(J, JS_CARRAY, J->Object_prototype);
197 J->Function_prototype = jsV_newobject(J, JS_CCFUNCTION, J->Object_prototype);
198 J->Boolean_prototype = jsV_newobject(J, JS_CBOOLEAN, J->Object_prototype);
199 J->Number_prototype = jsV_newobject(J, JS_CNUMBER, J->Object_prototype);
200 J->String_prototype = jsV_newobject(J, JS_CSTRING, J->Object_prototype);
201 J->RegExp_prototype = jsV_newobject(J, JS_COBJECT, J->Object_prototype);
202 J->Date_prototype = jsV_newobject(J, JS_CDATE, J->Object_prototype);
203
204 /* All the native error types */
205 J->Error_prototype = jsV_newobject(J, JS_CERROR, J->Object_prototype);
206 J->EvalError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype);
207 J->RangeError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype);
208 J->ReferenceError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype);
209 J->SyntaxError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype);
210 J->TypeError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype);
211 J->URIError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype);
212
213 /* Create the constructors and fill out the prototype objects */
214 jsB_initobject(J);
215 jsB_initarray(J);
216 jsB_initfunction(J);
217 jsB_initboolean(J);
218 jsB_initnumber(J);
219 jsB_initstring(J);
220 jsB_initregexp(J);
221 jsB_initdate(J);
222 jsB_initerror(J);
223 jsB_initmath(J);
224 jsB_initjson(J);
225
226 /* Initialize the global object */
227 js_pushnumber(J, NAN);
228 js_defglobal(J, "NaN", JS_READONLY | JS_DONTENUM | JS_DONTCONF);
229
230 js_pushnumber(J, INFINITY);
231 js_defglobal(J, "Infinity", JS_READONLY | JS_DONTENUM | JS_DONTCONF);
232
233 js_pushundefined(J);
234 js_defglobal(J, "undefined", JS_READONLY | JS_DONTENUM | JS_DONTCONF);
235
236 jsB_globalf(J, "parseInt", jsB_parseInt, 1);
237 jsB_globalf(J, "parseFloat", jsB_parseFloat, 1);
238 jsB_globalf(J, "isNaN", jsB_isNaN, 1);
239 jsB_globalf(J, "isFinite", jsB_isFinite, 1);
240
241 jsB_globalf(J, "decodeURI", jsB_decodeURI, 1);
242 jsB_globalf(J, "decodeURIComponent", jsB_decodeURIComponent, 1);
243 jsB_globalf(J, "encodeURI", jsB_encodeURI, 1);
244 jsB_globalf(J, "encodeURIComponent", jsB_encodeURIComponent, 1);
245}
246