Coverage Report

Created: 2025-01-28 06:17

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