1 #include "jsi.h"
2 #include "jslex.h"
3 #include "jscompile.h"
4 #include "jsvalue.h"
5 #include "jsbuiltin.h"
6 
jsB_globalf(js_State * J,const char * name,js_CFunction cfun,int n)7 static 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 
jsB_propf(js_State * J,const char * name,js_CFunction cfun,int n)13 void 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 
jsB_propn(js_State * J,const char * name,double number)21 void 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 
jsB_props(js_State * J,const char * name,const char * string)27 void 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 
jsB_parseInt(js_State * J)33 static 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 
jsB_parseFloat(js_State * J)66 static 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 
jsB_isNaN(js_State * J)88 static void jsB_isNaN(js_State *J)
89 {
90 	double n = js_tonumber(J, 1);
91 	js_pushboolean(J, isnan(n));
92 }
93 
jsB_isFinite(js_State * J)94 static void jsB_isFinite(js_State *J)
95 {
96 	double n = js_tonumber(J, 1);
97 	js_pushboolean(J, isfinite(n));
98 }
99 
Encode(js_State * J,const char * str,const char * unescaped)100 static 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 
Decode(js_State * J,const char * str,const char * reserved)128 static 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 
jsB_decodeURI(js_State * J)172 static void jsB_decodeURI(js_State *J)
173 {
174 	Decode(J, js_tostring(J, 1), URIRESERVED "#");
175 }
176 
jsB_decodeURIComponent(js_State * J)177 static void jsB_decodeURIComponent(js_State *J)
178 {
179 	Decode(J, js_tostring(J, 1), "");
180 }
181 
jsB_encodeURI(js_State * J)182 static void jsB_encodeURI(js_State *J)
183 {
184 	Encode(J, js_tostring(J, 1), URIUNESCAPED URIRESERVED "#");
185 }
186 
jsB_encodeURIComponent(js_State * J)187 static void jsB_encodeURIComponent(js_State *J)
188 {
189 	Encode(J, js_tostring(J, 1), URIUNESCAPED);
190 }
191 
jsB_init(js_State * J)192 void 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