/src/mupdf/thirdparty/mujs/jsstring.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "jsi.h" |
2 | | #include "utf.h" |
3 | | #include "regexp.h" |
4 | | |
5 | | static int js_doregexec(js_State *J, Reprog *prog, const char *string, Resub *sub, int eflags) |
6 | 0 | { |
7 | 0 | int result = js_regexec(prog, string, sub, eflags); |
8 | 0 | if (result < 0) |
9 | 0 | js_error(J, "regexec failed"); |
10 | 0 | return result; |
11 | 0 | } |
12 | | |
13 | | static const char *checkstring(js_State *J, int idx) |
14 | 0 | { |
15 | 0 | if (!js_iscoercible(J, idx)) |
16 | 0 | js_typeerror(J, "string function called on null or undefined"); |
17 | 0 | return js_tostring(J, idx); |
18 | 0 | } |
19 | | |
20 | | int js_runeat(js_State *J, const char *s, int i) |
21 | 0 | { |
22 | 0 | Rune rune = EOF; |
23 | 0 | while (i-- >= 0) { |
24 | 0 | rune = *(unsigned char*)s; |
25 | 0 | if (rune < Runeself) { |
26 | 0 | if (rune == 0) |
27 | 0 | return EOF; |
28 | 0 | ++s; |
29 | 0 | } else |
30 | 0 | s += chartorune(&rune, s); |
31 | 0 | } |
32 | 0 | return rune; |
33 | 0 | } |
34 | | |
35 | | const char *js_utfidxtoptr(const char *s, int i) |
36 | 0 | { |
37 | 0 | Rune rune; |
38 | 0 | while (i-- > 0) { |
39 | 0 | rune = *(unsigned char*)s; |
40 | 0 | if (rune < Runeself) { |
41 | 0 | if (rune == 0) |
42 | 0 | return NULL; |
43 | 0 | ++s; |
44 | 0 | } else |
45 | 0 | s += chartorune(&rune, s); |
46 | 0 | } |
47 | 0 | return s; |
48 | 0 | } |
49 | | |
50 | | int js_utfptrtoidx(const char *s, const char *p) |
51 | 0 | { |
52 | 0 | Rune rune; |
53 | 0 | int i = 0; |
54 | 0 | while (s < p) { |
55 | 0 | if (*(unsigned char *)s < Runeself) |
56 | 0 | ++s; |
57 | 0 | else |
58 | 0 | s += chartorune(&rune, s); |
59 | 0 | ++i; |
60 | 0 | } |
61 | 0 | return i; |
62 | 0 | } |
63 | | |
64 | | static void jsB_new_String(js_State *J) |
65 | 0 | { |
66 | 0 | js_newstring(J, js_gettop(J) > 1 ? js_tostring(J, 1) : ""); |
67 | 0 | } |
68 | | |
69 | | static void jsB_String(js_State *J) |
70 | 0 | { |
71 | 0 | js_pushstring(J, js_gettop(J) > 1 ? js_tostring(J, 1) : ""); |
72 | 0 | } |
73 | | |
74 | | static void Sp_toString(js_State *J) |
75 | 0 | { |
76 | 0 | js_Object *self = js_toobject(J, 0); |
77 | 0 | if (self->type != JS_CSTRING) js_typeerror(J, "not a string"); |
78 | 0 | js_pushstring(J, self->u.s.string); |
79 | 0 | } |
80 | | |
81 | | static void Sp_valueOf(js_State *J) |
82 | 0 | { |
83 | 0 | js_Object *self = js_toobject(J, 0); |
84 | 0 | if (self->type != JS_CSTRING) js_typeerror(J, "not a string"); |
85 | 0 | js_pushstring(J, self->u.s.string); |
86 | 0 | } |
87 | | |
88 | | static void Sp_charAt(js_State *J) |
89 | 0 | { |
90 | 0 | char buf[UTFmax + 1]; |
91 | 0 | const char *s = checkstring(J, 0); |
92 | 0 | int pos = js_tointeger(J, 1); |
93 | 0 | Rune rune = js_runeat(J, s, pos); |
94 | 0 | if (rune >= 0) { |
95 | 0 | buf[runetochar(buf, &rune)] = 0; |
96 | 0 | js_pushstring(J, buf); |
97 | 0 | } else { |
98 | 0 | js_pushliteral(J, ""); |
99 | 0 | } |
100 | 0 | } |
101 | | |
102 | | static void Sp_charCodeAt(js_State *J) |
103 | 0 | { |
104 | 0 | const char *s = checkstring(J, 0); |
105 | 0 | int pos = js_tointeger(J, 1); |
106 | 0 | Rune rune = js_runeat(J, s, pos); |
107 | 0 | if (rune >= 0) |
108 | 0 | js_pushnumber(J, rune); |
109 | 0 | else |
110 | 0 | js_pushnumber(J, NAN); |
111 | 0 | } |
112 | | |
113 | | static void Sp_concat(js_State *J) |
114 | 0 | { |
115 | 0 | int i, top = js_gettop(J); |
116 | 0 | int n; |
117 | 0 | char * volatile out = NULL; |
118 | 0 | const char *s; |
119 | |
|
120 | 0 | if (top == 1) |
121 | 0 | return; |
122 | | |
123 | 0 | s = checkstring(J, 0); |
124 | 0 | n = 1 + strlen(s); |
125 | |
|
126 | 0 | if (js_try(J)) { |
127 | 0 | js_free(J, out); |
128 | 0 | js_throw(J); |
129 | 0 | } |
130 | | |
131 | 0 | if (n > JS_STRLIMIT) |
132 | 0 | js_rangeerror(J, "invalid string length"); |
133 | 0 | out = js_malloc(J, n); |
134 | 0 | strcpy(out, s); |
135 | |
|
136 | 0 | for (i = 1; i < top; ++i) { |
137 | 0 | s = js_tostring(J, i); |
138 | 0 | n += strlen(s); |
139 | 0 | if (n > JS_STRLIMIT) |
140 | 0 | js_rangeerror(J, "invalid string length"); |
141 | 0 | out = js_realloc(J, out, n); |
142 | 0 | strcat(out, s); |
143 | 0 | } |
144 | | |
145 | 0 | js_pushstring(J, out); |
146 | 0 | js_endtry(J); |
147 | 0 | js_free(J, out); |
148 | 0 | } |
149 | | |
150 | | static void Sp_indexOf(js_State *J) |
151 | 0 | { |
152 | 0 | const char *haystack = checkstring(J, 0); |
153 | 0 | const char *needle = js_tostring(J, 1); |
154 | 0 | int pos = js_tointeger(J, 2); |
155 | 0 | int len = strlen(needle); |
156 | 0 | int k = 0; |
157 | 0 | Rune rune; |
158 | 0 | while (*haystack) { |
159 | 0 | if (k >= pos && !strncmp(haystack, needle, len)) { |
160 | 0 | js_pushnumber(J, k); |
161 | 0 | return; |
162 | 0 | } |
163 | 0 | haystack += chartorune(&rune, haystack); |
164 | 0 | ++k; |
165 | 0 | } |
166 | 0 | js_pushnumber(J, -1); |
167 | 0 | } |
168 | | |
169 | | static void Sp_lastIndexOf(js_State *J) |
170 | 0 | { |
171 | 0 | const char *haystack = checkstring(J, 0); |
172 | 0 | const char *needle = js_tostring(J, 1); |
173 | 0 | int pos = js_isdefined(J, 2) ? js_tointeger(J, 2) : (int)strlen(haystack); |
174 | 0 | int len = strlen(needle); |
175 | 0 | int k = 0, last = -1; |
176 | 0 | Rune rune; |
177 | 0 | while (*haystack && k <= pos) { |
178 | 0 | if (!strncmp(haystack, needle, len)) |
179 | 0 | last = k; |
180 | 0 | haystack += chartorune(&rune, haystack); |
181 | 0 | ++k; |
182 | 0 | } |
183 | 0 | js_pushnumber(J, last); |
184 | 0 | } |
185 | | |
186 | | static void Sp_localeCompare(js_State *J) |
187 | 0 | { |
188 | 0 | const char *a = checkstring(J, 0); |
189 | 0 | const char *b = js_tostring(J, 1); |
190 | 0 | js_pushnumber(J, strcmp(a, b)); |
191 | 0 | } |
192 | | |
193 | | static void Sp_slice(js_State *J) |
194 | 0 | { |
195 | 0 | const char *str = checkstring(J, 0); |
196 | 0 | const char *ss, *ee; |
197 | 0 | int len = utflen(str); |
198 | 0 | int s = js_tointeger(J, 1); |
199 | 0 | int e = js_isdefined(J, 2) ? js_tointeger(J, 2) : len; |
200 | |
|
201 | 0 | s = s < 0 ? s + len : s; |
202 | 0 | e = e < 0 ? e + len : e; |
203 | |
|
204 | 0 | s = s < 0 ? 0 : s > len ? len : s; |
205 | 0 | e = e < 0 ? 0 : e > len ? len : e; |
206 | |
|
207 | 0 | if (s < e) { |
208 | 0 | ss = js_utfidxtoptr(str, s); |
209 | 0 | ee = js_utfidxtoptr(ss, e - s); |
210 | 0 | } else { |
211 | 0 | ss = js_utfidxtoptr(str, e); |
212 | 0 | ee = js_utfidxtoptr(ss, s - e); |
213 | 0 | } |
214 | |
|
215 | 0 | js_pushlstring(J, ss, ee - ss); |
216 | 0 | } |
217 | | |
218 | | static void Sp_substring(js_State *J) |
219 | 0 | { |
220 | 0 | const char *str = checkstring(J, 0); |
221 | 0 | const char *ss, *ee; |
222 | 0 | int len = utflen(str); |
223 | 0 | int s = js_tointeger(J, 1); |
224 | 0 | int e = js_isdefined(J, 2) ? js_tointeger(J, 2) : len; |
225 | |
|
226 | 0 | s = s < 0 ? 0 : s > len ? len : s; |
227 | 0 | e = e < 0 ? 0 : e > len ? len : e; |
228 | |
|
229 | 0 | if (s < e) { |
230 | 0 | ss = js_utfidxtoptr(str, s); |
231 | 0 | ee = js_utfidxtoptr(ss, e - s); |
232 | 0 | } else { |
233 | 0 | ss = js_utfidxtoptr(str, e); |
234 | 0 | ee = js_utfidxtoptr(ss, s - e); |
235 | 0 | } |
236 | |
|
237 | 0 | js_pushlstring(J, ss, ee - ss); |
238 | 0 | } |
239 | | |
240 | | static void Sp_toLowerCase(js_State *J) |
241 | 0 | { |
242 | 0 | const char *s = checkstring(J, 0); |
243 | 0 | char * volatile dst = NULL; |
244 | 0 | char *d; |
245 | 0 | Rune rune; |
246 | |
|
247 | 0 | if (js_try(J)) { |
248 | 0 | js_free(J, dst); |
249 | 0 | js_throw(J); |
250 | 0 | } |
251 | | |
252 | 0 | d = dst = js_malloc(J, UTFmax * strlen(s) + 1); |
253 | 0 | while (*s) { |
254 | 0 | s += chartorune(&rune, s); |
255 | 0 | rune = tolowerrune(rune); |
256 | 0 | d += runetochar(d, &rune); |
257 | 0 | } |
258 | 0 | *d = 0; |
259 | |
|
260 | 0 | js_pushstring(J, dst); |
261 | 0 | js_endtry(J); |
262 | 0 | js_free(J, dst); |
263 | 0 | } |
264 | | |
265 | | static void Sp_toUpperCase(js_State *J) |
266 | 0 | { |
267 | 0 | const char *s = checkstring(J, 0); |
268 | 0 | char * volatile dst = NULL; |
269 | 0 | char *d; |
270 | 0 | Rune rune; |
271 | |
|
272 | 0 | if (js_try(J)) { |
273 | 0 | js_free(J, dst); |
274 | 0 | js_throw(J); |
275 | 0 | } |
276 | | |
277 | 0 | d = dst = js_malloc(J, UTFmax * strlen(s) + 1); |
278 | 0 | while (*s) { |
279 | 0 | s += chartorune(&rune, s); |
280 | 0 | rune = toupperrune(rune); |
281 | 0 | d += runetochar(d, &rune); |
282 | 0 | } |
283 | 0 | *d = 0; |
284 | |
|
285 | 0 | js_pushstring(J, dst); |
286 | 0 | js_endtry(J); |
287 | 0 | js_free(J, dst); |
288 | 0 | } |
289 | | |
290 | | static int istrim(int c) |
291 | 0 | { |
292 | 0 | return c == 0x9 || c == 0xB || c == 0xC || c == 0x20 || c == 0xA0 || c == 0xFEFF || |
293 | 0 | c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029; |
294 | 0 | } |
295 | | |
296 | | static void Sp_trim(js_State *J) |
297 | 0 | { |
298 | 0 | const char *s, *e; |
299 | 0 | s = checkstring(J, 0); |
300 | 0 | while (istrim(*s)) |
301 | 0 | ++s; |
302 | 0 | e = s + strlen(s); |
303 | 0 | while (e > s && istrim(e[-1])) |
304 | 0 | --e; |
305 | 0 | js_pushlstring(J, s, e - s); |
306 | 0 | } |
307 | | |
308 | | static void S_fromCharCode(js_State *J) |
309 | 0 | { |
310 | 0 | int i, top = js_gettop(J); |
311 | 0 | char * volatile s = NULL; |
312 | 0 | char *p; |
313 | 0 | Rune c; |
314 | |
|
315 | 0 | if (js_try(J)) { |
316 | 0 | js_free(J, s); |
317 | 0 | js_throw(J); |
318 | 0 | } |
319 | | |
320 | 0 | s = p = js_malloc(J, (top-1) * UTFmax + 1); |
321 | |
|
322 | 0 | for (i = 1; i < top; ++i) { |
323 | 0 | c = js_touint32(J, i); |
324 | 0 | p += runetochar(p, &c); |
325 | 0 | } |
326 | 0 | *p = 0; |
327 | |
|
328 | 0 | js_pushstring(J, s); |
329 | 0 | js_endtry(J); |
330 | 0 | js_free(J, s); |
331 | 0 | } |
332 | | |
333 | | static void Sp_match(js_State *J) |
334 | 0 | { |
335 | 0 | js_Regexp *re; |
336 | 0 | const char *text; |
337 | 0 | int len; |
338 | 0 | const char *a, *b, *c, *e; |
339 | 0 | Resub m; |
340 | |
|
341 | 0 | text = checkstring(J, 0); |
342 | |
|
343 | 0 | if (js_isregexp(J, 1)) |
344 | 0 | js_copy(J, 1); |
345 | 0 | else if (js_isundefined(J, 1)) |
346 | 0 | js_newregexp(J, "", 0); |
347 | 0 | else |
348 | 0 | js_newregexp(J, js_tostring(J, 1), 0); |
349 | |
|
350 | 0 | re = js_toregexp(J, -1); |
351 | 0 | if (!(re->flags & JS_REGEXP_G)) { |
352 | 0 | js_RegExp_prototype_exec(J, re, text); |
353 | 0 | return; |
354 | 0 | } |
355 | | |
356 | 0 | re->last = 0; |
357 | |
|
358 | 0 | js_newarray(J); |
359 | |
|
360 | 0 | len = 0; |
361 | 0 | a = text; |
362 | 0 | e = text + strlen(text); |
363 | 0 | while (a <= e) { |
364 | 0 | if (js_doregexec(J, re->prog, a, &m, a > text ? REG_NOTBOL : 0)) |
365 | 0 | break; |
366 | | |
367 | 0 | b = m.sub[0].sp; |
368 | 0 | c = m.sub[0].ep; |
369 | |
|
370 | 0 | js_pushlstring(J, b, c - b); |
371 | 0 | js_setindex(J, -2, len++); |
372 | |
|
373 | 0 | a = c; |
374 | 0 | if (c - b == 0) |
375 | 0 | ++a; |
376 | 0 | } |
377 | |
|
378 | 0 | if (len == 0) { |
379 | 0 | js_pop(J, 1); |
380 | 0 | js_pushnull(J); |
381 | 0 | } |
382 | 0 | } |
383 | | |
384 | | static void Sp_search(js_State *J) |
385 | 0 | { |
386 | 0 | js_Regexp *re; |
387 | 0 | const char *text; |
388 | 0 | Resub m; |
389 | |
|
390 | 0 | text = checkstring(J, 0); |
391 | |
|
392 | 0 | if (js_isregexp(J, 1)) |
393 | 0 | js_copy(J, 1); |
394 | 0 | else if (js_isundefined(J, 1)) |
395 | 0 | js_newregexp(J, "", 0); |
396 | 0 | else |
397 | 0 | js_newregexp(J, js_tostring(J, 1), 0); |
398 | |
|
399 | 0 | re = js_toregexp(J, -1); |
400 | |
|
401 | 0 | if (!js_doregexec(J, re->prog, text, &m, 0)) |
402 | 0 | js_pushnumber(J, js_utfptrtoidx(text, m.sub[0].sp)); |
403 | 0 | else |
404 | 0 | js_pushnumber(J, -1); |
405 | 0 | } |
406 | | |
407 | | static void Sp_replace_regexp(js_State *J) |
408 | 0 | { |
409 | 0 | js_Regexp *re; |
410 | 0 | const char *source, *s, *r; |
411 | 0 | js_Buffer *sb = NULL; |
412 | 0 | int n, x; |
413 | 0 | Resub m; |
414 | |
|
415 | 0 | source = checkstring(J, 0); |
416 | 0 | re = js_toregexp(J, 1); |
417 | |
|
418 | 0 | if (js_doregexec(J, re->prog, source, &m, 0)) { |
419 | 0 | js_copy(J, 0); |
420 | 0 | return; |
421 | 0 | } |
422 | | |
423 | 0 | re->last = 0; |
424 | |
|
425 | 0 | loop: |
426 | 0 | s = m.sub[0].sp; |
427 | 0 | n = m.sub[0].ep - m.sub[0].sp; |
428 | |
|
429 | 0 | if (js_iscallable(J, 2)) { |
430 | 0 | js_copy(J, 2); |
431 | 0 | js_pushundefined(J); |
432 | 0 | for (x = 0; m.sub[x].sp; ++x) /* arg 0..x: substring and subexps that matched */ |
433 | 0 | js_pushlstring(J, m.sub[x].sp, m.sub[x].ep - m.sub[x].sp); |
434 | 0 | js_pushnumber(J, s - source); /* arg x+2: offset within search string */ |
435 | 0 | js_copy(J, 0); /* arg x+3: search string */ |
436 | 0 | js_call(J, 2 + x); |
437 | 0 | r = js_tostring(J, -1); |
438 | 0 | js_putm(J, &sb, source, s); |
439 | 0 | js_puts(J, &sb, r); |
440 | 0 | js_pop(J, 1); |
441 | 0 | } else { |
442 | 0 | r = js_tostring(J, 2); |
443 | 0 | js_putm(J, &sb, source, s); |
444 | 0 | while (*r) { |
445 | 0 | if (*r == '$') { |
446 | 0 | switch (*(++r)) { |
447 | 0 | case 0: --r; /* end of string; back up */ |
448 | | /* fallthrough */ |
449 | 0 | case '$': js_putc(J, &sb, '$'); break; |
450 | 0 | case '`': js_putm(J, &sb, source, s); break; |
451 | 0 | case '\'': js_puts(J, &sb, s + n); break; |
452 | 0 | case '&': |
453 | 0 | js_putm(J, &sb, s, s + n); |
454 | 0 | break; |
455 | 0 | case '0': case '1': case '2': case '3': case '4': |
456 | 0 | case '5': case '6': case '7': case '8': case '9': |
457 | 0 | x = *r - '0'; |
458 | 0 | if (r[1] >= '0' && r[1] <= '9') |
459 | 0 | x = x * 10 + *(++r) - '0'; |
460 | 0 | if (x > 0 && x < m.nsub) { |
461 | 0 | js_putm(J, &sb, m.sub[x].sp, m.sub[x].ep); |
462 | 0 | } else { |
463 | 0 | js_putc(J, &sb, '$'); |
464 | 0 | if (x > 10) { |
465 | 0 | js_putc(J, &sb, '0' + x / 10); |
466 | 0 | js_putc(J, &sb, '0' + x % 10); |
467 | 0 | } else { |
468 | 0 | js_putc(J, &sb, '0' + x); |
469 | 0 | } |
470 | 0 | } |
471 | 0 | break; |
472 | 0 | default: |
473 | 0 | js_putc(J, &sb, '$'); |
474 | 0 | js_putc(J, &sb, *r); |
475 | 0 | break; |
476 | 0 | } |
477 | 0 | ++r; |
478 | 0 | } else { |
479 | 0 | js_putc(J, &sb, *r++); |
480 | 0 | } |
481 | 0 | } |
482 | 0 | } |
483 | | |
484 | 0 | if (re->flags & JS_REGEXP_G) { |
485 | 0 | source = m.sub[0].ep; |
486 | 0 | if (n == 0) { |
487 | 0 | if (*source) |
488 | 0 | js_putc(J, &sb, *source++); |
489 | 0 | else |
490 | 0 | goto end; |
491 | 0 | } |
492 | 0 | if (!js_doregexec(J, re->prog, source, &m, REG_NOTBOL)) |
493 | 0 | goto loop; |
494 | 0 | } |
495 | | |
496 | 0 | end: |
497 | 0 | js_puts(J, &sb, s + n); |
498 | 0 | js_putc(J, &sb, 0); |
499 | |
|
500 | 0 | if (js_try(J)) { |
501 | 0 | js_free(J, sb); |
502 | 0 | js_throw(J); |
503 | 0 | } |
504 | 0 | js_pushstring(J, sb ? sb->s : ""); |
505 | 0 | js_endtry(J); |
506 | 0 | js_free(J, sb); |
507 | 0 | } |
508 | | |
509 | | static void Sp_replace_string(js_State *J) |
510 | 0 | { |
511 | 0 | const char *source, *needle, *s, *r; |
512 | 0 | js_Buffer *sb = NULL; |
513 | 0 | int n; |
514 | |
|
515 | 0 | source = checkstring(J, 0); |
516 | 0 | needle = js_tostring(J, 1); |
517 | |
|
518 | 0 | s = strstr(source, needle); |
519 | 0 | if (!s) { |
520 | 0 | js_copy(J, 0); |
521 | 0 | return; |
522 | 0 | } |
523 | 0 | n = strlen(needle); |
524 | |
|
525 | 0 | if (js_iscallable(J, 2)) { |
526 | 0 | js_copy(J, 2); |
527 | 0 | js_pushundefined(J); |
528 | 0 | js_pushlstring(J, s, n); /* arg 1: substring that matched */ |
529 | 0 | js_pushnumber(J, s - source); /* arg 2: offset within search string */ |
530 | 0 | js_copy(J, 0); /* arg 3: search string */ |
531 | 0 | js_call(J, 3); |
532 | 0 | r = js_tostring(J, -1); |
533 | 0 | js_putm(J, &sb, source, s); |
534 | 0 | js_puts(J, &sb, r); |
535 | 0 | js_puts(J, &sb, s + n); |
536 | 0 | js_putc(J, &sb, 0); |
537 | 0 | js_pop(J, 1); |
538 | 0 | } else { |
539 | 0 | r = js_tostring(J, 2); |
540 | 0 | js_putm(J, &sb, source, s); |
541 | 0 | while (*r) { |
542 | 0 | if (*r == '$') { |
543 | 0 | switch (*(++r)) { |
544 | 0 | case 0: --r; /* end of string; back up */ |
545 | | /* fallthrough */ |
546 | 0 | case '$': js_putc(J, &sb, '$'); break; |
547 | 0 | case '&': js_putm(J, &sb, s, s + n); break; |
548 | 0 | case '`': js_putm(J, &sb, source, s); break; |
549 | 0 | case '\'': js_puts(J, &sb, s + n); break; |
550 | 0 | default: js_putc(J, &sb, '$'); js_putc(J, &sb, *r); break; |
551 | 0 | } |
552 | 0 | ++r; |
553 | 0 | } else { |
554 | 0 | js_putc(J, &sb, *r++); |
555 | 0 | } |
556 | 0 | } |
557 | 0 | js_puts(J, &sb, s + n); |
558 | 0 | js_putc(J, &sb, 0); |
559 | 0 | } |
560 | | |
561 | 0 | if (js_try(J)) { |
562 | 0 | js_free(J, sb); |
563 | 0 | js_throw(J); |
564 | 0 | } |
565 | 0 | js_pushstring(J, sb ? sb->s : ""); |
566 | 0 | js_endtry(J); |
567 | 0 | js_free(J, sb); |
568 | 0 | } |
569 | | |
570 | | static void Sp_replace(js_State *J) |
571 | 0 | { |
572 | 0 | if (js_isregexp(J, 1)) |
573 | 0 | Sp_replace_regexp(J); |
574 | 0 | else |
575 | 0 | Sp_replace_string(J); |
576 | 0 | } |
577 | | |
578 | | static void Sp_split_regexp(js_State *J) |
579 | 0 | { |
580 | 0 | js_Regexp *re; |
581 | 0 | const char *text; |
582 | 0 | int limit, len, k; |
583 | 0 | const char *p, *a, *b, *c, *e; |
584 | 0 | Resub m; |
585 | |
|
586 | 0 | text = checkstring(J, 0); |
587 | 0 | re = js_toregexp(J, 1); |
588 | 0 | limit = js_isdefined(J, 2) ? js_tointeger(J, 2) : 1 << 30; |
589 | |
|
590 | 0 | js_newarray(J); |
591 | 0 | len = 0; |
592 | |
|
593 | 0 | e = text + strlen(text); |
594 | | |
595 | | /* splitting the empty string */ |
596 | 0 | if (e == text) { |
597 | 0 | if (js_doregexec(J, re->prog, text, &m, 0)) { |
598 | 0 | if (len == limit) return; |
599 | 0 | js_pushliteral(J, ""); |
600 | 0 | js_setindex(J, -2, 0); |
601 | 0 | } |
602 | 0 | return; |
603 | 0 | } |
604 | | |
605 | 0 | p = a = text; |
606 | 0 | while (a < e) { |
607 | 0 | if (js_doregexec(J, re->prog, a, &m, a > text ? REG_NOTBOL : 0)) |
608 | 0 | break; /* no match */ |
609 | | |
610 | 0 | b = m.sub[0].sp; |
611 | 0 | c = m.sub[0].ep; |
612 | | |
613 | | /* empty string at end of last match */ |
614 | 0 | if (b == p) { |
615 | 0 | ++a; |
616 | 0 | continue; |
617 | 0 | } |
618 | | |
619 | 0 | if (len == limit) return; |
620 | 0 | js_pushlstring(J, p, b - p); |
621 | 0 | js_setindex(J, -2, len++); |
622 | |
|
623 | 0 | for (k = 1; k < m.nsub; ++k) { |
624 | 0 | if (len == limit) return; |
625 | 0 | js_pushlstring(J, m.sub[k].sp, m.sub[k].ep - m.sub[k].sp); |
626 | 0 | js_setindex(J, -2, len++); |
627 | 0 | } |
628 | | |
629 | 0 | a = p = c; |
630 | 0 | } |
631 | | |
632 | 0 | if (len == limit) return; |
633 | 0 | js_pushstring(J, p); |
634 | 0 | js_setindex(J, -2, len); |
635 | 0 | } |
636 | | |
637 | | static void Sp_split_string(js_State *J) |
638 | 0 | { |
639 | 0 | const char *str = checkstring(J, 0); |
640 | 0 | const char *sep = js_tostring(J, 1); |
641 | 0 | int limit = js_isdefined(J, 2) ? js_tointeger(J, 2) : 1 << 30; |
642 | 0 | int i, n; |
643 | |
|
644 | 0 | js_newarray(J); |
645 | |
|
646 | 0 | n = strlen(sep); |
647 | | |
648 | | /* empty string */ |
649 | 0 | if (n == 0) { |
650 | 0 | Rune rune; |
651 | 0 | for (i = 0; *str && i < limit; ++i) { |
652 | 0 | n = chartorune(&rune, str); |
653 | 0 | js_pushlstring(J, str, n); |
654 | 0 | js_setindex(J, -2, i); |
655 | 0 | str += n; |
656 | 0 | } |
657 | 0 | return; |
658 | 0 | } |
659 | | |
660 | 0 | for (i = 0; str && i < limit; ++i) { |
661 | 0 | const char *s = strstr(str, sep); |
662 | 0 | if (s) { |
663 | 0 | js_pushlstring(J, str, s-str); |
664 | 0 | js_setindex(J, -2, i); |
665 | 0 | str = s + n; |
666 | 0 | } else { |
667 | 0 | js_pushstring(J, str); |
668 | 0 | js_setindex(J, -2, i); |
669 | 0 | str = NULL; |
670 | 0 | } |
671 | 0 | } |
672 | 0 | } |
673 | | |
674 | | static void Sp_split(js_State *J) |
675 | 0 | { |
676 | 0 | if (js_isundefined(J, 1)) { |
677 | 0 | js_newarray(J); |
678 | 0 | js_pushstring(J, js_tostring(J, 0)); |
679 | 0 | js_setindex(J, -2, 0); |
680 | 0 | } else if (js_isregexp(J, 1)) { |
681 | 0 | Sp_split_regexp(J); |
682 | 0 | } else { |
683 | 0 | Sp_split_string(J); |
684 | 0 | } |
685 | 0 | } |
686 | | |
687 | | void jsB_initstring(js_State *J) |
688 | 0 | { |
689 | 0 | J->String_prototype->u.s.shrstr[0] = 0; |
690 | 0 | J->String_prototype->u.s.string = J->String_prototype->u.s.shrstr; |
691 | 0 | J->String_prototype->u.s.length = 0; |
692 | |
|
693 | 0 | js_pushobject(J, J->String_prototype); |
694 | 0 | { |
695 | 0 | jsB_propf(J, "String.prototype.toString", Sp_toString, 0); |
696 | 0 | jsB_propf(J, "String.prototype.valueOf", Sp_valueOf, 0); |
697 | 0 | jsB_propf(J, "String.prototype.charAt", Sp_charAt, 1); |
698 | 0 | jsB_propf(J, "String.prototype.charCodeAt", Sp_charCodeAt, 1); |
699 | 0 | jsB_propf(J, "String.prototype.concat", Sp_concat, 0); /* 1 */ |
700 | 0 | jsB_propf(J, "String.prototype.indexOf", Sp_indexOf, 1); |
701 | 0 | jsB_propf(J, "String.prototype.lastIndexOf", Sp_lastIndexOf, 1); |
702 | 0 | jsB_propf(J, "String.prototype.localeCompare", Sp_localeCompare, 1); |
703 | 0 | jsB_propf(J, "String.prototype.match", Sp_match, 1); |
704 | 0 | jsB_propf(J, "String.prototype.replace", Sp_replace, 2); |
705 | 0 | jsB_propf(J, "String.prototype.search", Sp_search, 1); |
706 | 0 | jsB_propf(J, "String.prototype.slice", Sp_slice, 2); |
707 | 0 | jsB_propf(J, "String.prototype.split", Sp_split, 2); |
708 | 0 | jsB_propf(J, "String.prototype.substring", Sp_substring, 2); |
709 | 0 | jsB_propf(J, "String.prototype.toLowerCase", Sp_toLowerCase, 0); |
710 | 0 | jsB_propf(J, "String.prototype.toLocaleLowerCase", Sp_toLowerCase, 0); |
711 | 0 | jsB_propf(J, "String.prototype.toUpperCase", Sp_toUpperCase, 0); |
712 | 0 | jsB_propf(J, "String.prototype.toLocaleUpperCase", Sp_toUpperCase, 0); |
713 | | |
714 | | /* ES5 */ |
715 | 0 | jsB_propf(J, "String.prototype.trim", Sp_trim, 0); |
716 | 0 | } |
717 | 0 | js_newcconstructor(J, jsB_String, jsB_new_String, "String", 0); /* 1 */ |
718 | 0 | { |
719 | 0 | jsB_propf(J, "String.fromCharCode", S_fromCharCode, 0); /* 1 */ |
720 | 0 | } |
721 | 0 | js_defglobal(J, "String", JS_DONTENUM); |
722 | 0 | } |