Coverage Report

Created: 2025-11-07 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mupdf/thirdparty/mujs/jsstring.c
Line
Count
Source
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 if (s > e)
292
0
    Sp_substring_imp(J, str, e, s - e);
293
0
  else
294
0
    js_pushliteral(J, "");
295
0
}
296
297
static void Sp_substring(js_State *J)
298
0
{
299
0
  const char *str = checkstring(J, 0);
300
0
  int len = js_utflen(str);
301
0
  int s = js_tointeger(J, 1);
302
0
  int e = js_isdefined(J, 2) ? js_tointeger(J, 2) : len;
303
304
0
  s = s < 0 ? 0 : s > len ? len : s;
305
0
  e = e < 0 ? 0 : e > len ? len : e;
306
307
0
  if (s < e)
308
0
    Sp_substring_imp(J, str, s, e - s);
309
0
  else if (s > e)
310
0
    Sp_substring_imp(J, str, e, s - e);
311
0
  else
312
0
    js_pushliteral(J, "");
313
0
}
314
315
static void Sp_toLowerCase(js_State *J)
316
0
{
317
0
  const char *s, *s0 = checkstring(J, 0);
318
0
  char * volatile dst = NULL;
319
0
  char *d;
320
0
  Rune rune;
321
0
  const Rune *full;
322
0
  int n;
323
324
0
  n = 1;
325
0
  for (s = s0; *s;) {
326
0
    s += chartorune(&rune, s);
327
0
    full = tolowerrune_full(rune);
328
0
    if (full) {
329
0
      while (*full) {
330
0
        n += runelen(*full);
331
0
        ++full;
332
0
      }
333
0
    } else {
334
0
      rune = tolowerrune(rune);
335
0
      n += runelen(rune);
336
0
    }
337
0
  }
338
339
0
  if (js_try(J)) {
340
0
    js_free(J, dst);
341
0
    js_throw(J);
342
0
  }
343
344
0
  d = dst = js_malloc(J, n);
345
0
  for (s = s0; *s;) {
346
0
    s += chartorune(&rune, s);
347
0
    full = tolowerrune_full(rune);
348
0
    if (full) {
349
0
      while (*full) {
350
0
        d += runetochar(d, full);
351
0
        ++full;
352
0
      }
353
0
    } else {
354
0
      rune = tolowerrune(rune);
355
0
      d += runetochar(d, &rune);
356
0
    }
357
0
  }
358
0
  *d = 0;
359
360
0
  js_pushstring(J, dst);
361
0
  js_endtry(J);
362
0
  js_free(J, dst);
363
0
}
364
365
static void Sp_toUpperCase(js_State *J)
366
0
{
367
0
  const char *s, *s0 = checkstring(J, 0);
368
0
  char * volatile dst = NULL;
369
0
  char *d;
370
0
  const Rune *full;
371
0
  Rune rune;
372
0
  int n;
373
374
0
  n = 1;
375
0
  for (s = s0; *s;) {
376
0
    s += chartorune(&rune, s);
377
0
    full = toupperrune_full(rune);
378
0
    if (full) {
379
0
      while (*full) {
380
0
        n += runelen(*full);
381
0
        ++full;
382
0
      }
383
0
    } else {
384
0
      rune = toupperrune(rune);
385
0
      n += runelen(rune);
386
0
    }
387
0
  }
388
389
0
  if (js_try(J)) {
390
0
    js_free(J, dst);
391
0
    js_throw(J);
392
0
  }
393
394
0
  d = dst = js_malloc(J, n);
395
0
  for (s = s0; *s;) {
396
0
    s += chartorune(&rune, s);
397
0
    full = toupperrune_full(rune);
398
0
    if (full) {
399
0
      while (*full) {
400
0
        d += runetochar(d, full);
401
0
        ++full;
402
0
      }
403
0
    } else {
404
0
      rune = toupperrune(rune);
405
0
      d += runetochar(d, &rune);
406
0
    }
407
0
  }
408
0
  *d = 0;
409
410
0
  js_pushstring(J, dst);
411
0
  js_endtry(J);
412
0
  js_free(J, dst);
413
0
}
414
415
static int istrim(int c)
416
0
{
417
0
  return c == 0x9 || c == 0xB || c == 0xC || c == 0x20 || c == 0xA0 || c == 0xFEFF ||
418
0
    c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029;
419
0
}
420
421
static void Sp_trim(js_State *J)
422
0
{
423
0
  const char *s, *e;
424
0
  s = checkstring(J, 0);
425
0
  while (istrim(*s))
426
0
    ++s;
427
0
  e = s + strlen(s);
428
0
  while (e > s && istrim(e[-1]))
429
0
    --e;
430
0
  js_pushlstring(J, s, e - s);
431
0
}
432
433
static void S_fromCharCode(js_State *J)
434
0
{
435
0
  int i, top = js_gettop(J);
436
0
  char * volatile s = NULL;
437
0
  char *p;
438
0
  Rune c;
439
440
0
  if (js_try(J)) {
441
0
    js_free(J, s);
442
0
    js_throw(J);
443
0
  }
444
445
0
  s = p = js_malloc(J, (top-1) * UTFmax + 1);
446
447
0
  for (i = 1; i < top; ++i) {
448
0
    c = js_touint32(J, i);
449
0
    p += runetochar(p, &c);
450
0
  }
451
0
  *p = 0;
452
453
0
  js_pushstring(J, s);
454
0
  js_endtry(J);
455
0
  js_free(J, s);
456
0
}
457
458
static void Sp_match(js_State *J)
459
0
{
460
0
  js_Regexp *re;
461
0
  const char *text;
462
0
  int len;
463
0
  const char *a, *b, *c, *e;
464
0
  Resub m;
465
466
0
  text = checkstring(J, 0);
467
468
0
  if (js_isregexp(J, 1))
469
0
    js_copy(J, 1);
470
0
  else if (js_isundefined(J, 1))
471
0
    js_newregexp(J, "", 0);
472
0
  else
473
0
    js_newregexp(J, js_tostring(J, 1), 0);
474
475
0
  re = js_toregexp(J, -1);
476
0
  if (!(re->flags & JS_REGEXP_G)) {
477
0
    js_RegExp_prototype_exec(J, re, text);
478
0
    return;
479
0
  }
480
481
0
  re->last = 0;
482
483
0
  js_newarray(J);
484
485
0
  len = 0;
486
0
  a = text;
487
0
  e = text + strlen(text);
488
0
  while (a <= e) {
489
0
    if (js_doregexec(J, re->prog, a, &m, a > text ? REG_NOTBOL : 0))
490
0
      break;
491
492
0
    b = m.sub[0].sp;
493
0
    c = m.sub[0].ep;
494
495
0
    js_pushlstring(J, b, c - b);
496
0
    js_setindex(J, -2, len++);
497
498
0
    a = c;
499
0
    if (c - b == 0)
500
0
      ++a;
501
0
  }
502
503
0
  if (len == 0) {
504
0
    js_pop(J, 1);
505
0
    js_pushnull(J);
506
0
  }
507
0
}
508
509
static void Sp_search(js_State *J)
510
0
{
511
0
  js_Regexp *re;
512
0
  const char *text;
513
0
  Resub m;
514
515
0
  text = checkstring(J, 0);
516
517
0
  if (js_isregexp(J, 1))
518
0
    js_copy(J, 1);
519
0
  else if (js_isundefined(J, 1))
520
0
    js_newregexp(J, "", 0);
521
0
  else
522
0
    js_newregexp(J, js_tostring(J, 1), 0);
523
524
0
  re = js_toregexp(J, -1);
525
526
0
  if (!js_doregexec(J, re->prog, text, &m, 0))
527
0
    js_pushnumber(J, js_utfptrtoidx(text, m.sub[0].sp));
528
0
  else
529
0
    js_pushnumber(J, -1);
530
0
}
531
532
static void Sp_replace_regexp(js_State *J)
533
0
{
534
0
  js_Regexp *re;
535
0
  const char *source, *s, *r;
536
0
  js_Buffer *sb = NULL;
537
0
  int n, x;
538
0
  Resub m;
539
540
0
  source = checkstring(J, 0);
541
0
  re = js_toregexp(J, 1);
542
543
0
  if (js_doregexec(J, re->prog, source, &m, 0)) {
544
0
    js_copy(J, 0);
545
0
    return;
546
0
  }
547
548
0
  re->last = 0;
549
550
0
loop:
551
0
  s = m.sub[0].sp;
552
0
  n = m.sub[0].ep - m.sub[0].sp;
553
554
0
  if (js_iscallable(J, 2)) {
555
0
    js_copy(J, 2);
556
0
    js_pushundefined(J);
557
0
    for (x = 0; m.sub[x].sp; ++x) /* arg 0..x: substring and subexps that matched */
558
0
      js_pushlstring(J, m.sub[x].sp, m.sub[x].ep - m.sub[x].sp);
559
0
    js_pushnumber(J, s - source); /* arg x+2: offset within search string */
560
0
    js_copy(J, 0); /* arg x+3: search string */
561
0
    js_call(J, 2 + x);
562
0
    r = js_tostring(J, -1);
563
0
    js_putm(J, &sb, source, s);
564
0
    js_puts(J, &sb, r);
565
0
    js_pop(J, 1);
566
0
  } else {
567
0
    r = js_tostring(J, 2);
568
0
    js_putm(J, &sb, source, s);
569
0
    while (*r) {
570
0
      if (*r == '$') {
571
0
        switch (*(++r)) {
572
0
        case 0: --r; /* end of string; back up */
573
        /* fallthrough */
574
0
        case '$': js_putc(J, &sb, '$'); break;
575
0
        case '`': js_putm(J, &sb, source, s); break;
576
0
        case '\'': js_puts(J, &sb, s + n); break;
577
0
        case '&':
578
0
          js_putm(J, &sb, s, s + n);
579
0
          break;
580
0
        case '0': case '1': case '2': case '3': case '4':
581
0
        case '5': case '6': case '7': case '8': case '9':
582
0
          x = *r - '0';
583
0
          if (r[1] >= '0' && r[1] <= '9')
584
0
            x = x * 10 + *(++r) - '0';
585
0
          if (x > 0 && x < m.nsub) {
586
0
            js_putm(J, &sb, m.sub[x].sp, m.sub[x].ep);
587
0
          } else {
588
0
            js_putc(J, &sb, '$');
589
0
            if (x > 10) {
590
0
              js_putc(J, &sb, '0' + x / 10);
591
0
              js_putc(J, &sb, '0' + x % 10);
592
0
            } else {
593
0
              js_putc(J, &sb, '0' + x);
594
0
            }
595
0
          }
596
0
          break;
597
0
        default:
598
0
          js_putc(J, &sb, '$');
599
0
          js_putc(J, &sb, *r);
600
0
          break;
601
0
        }
602
0
        ++r;
603
0
      } else {
604
0
        js_putc(J, &sb, *r++);
605
0
      }
606
0
    }
607
0
  }
608
609
0
  if (re->flags & JS_REGEXP_G) {
610
0
    source = m.sub[0].ep;
611
0
    if (n == 0) {
612
0
      if (*source)
613
0
        js_putc(J, &sb, *source++);
614
0
      else
615
0
        goto end;
616
0
    }
617
0
    if (!js_doregexec(J, re->prog, source, &m, REG_NOTBOL))
618
0
      goto loop;
619
0
  }
620
621
0
end:
622
0
  js_puts(J, &sb, s + n);
623
0
  js_putc(J, &sb, 0);
624
625
0
  if (js_try(J)) {
626
0
    js_free(J, sb);
627
0
    js_throw(J);
628
0
  }
629
0
  js_pushstring(J, sb ? sb->s : "");
630
0
  js_endtry(J);
631
0
  js_free(J, sb);
632
0
}
633
634
static void Sp_replace_string(js_State *J)
635
0
{
636
0
  const char *source, *needle, *s, *r;
637
0
  js_Buffer *sb = NULL;
638
0
  int n;
639
640
0
  source = checkstring(J, 0);
641
0
  needle = js_tostring(J, 1);
642
643
0
  s = strstr(source, needle);
644
0
  if (!s) {
645
0
    js_copy(J, 0);
646
0
    return;
647
0
  }
648
0
  n = strlen(needle);
649
650
0
  if (js_iscallable(J, 2)) {
651
0
    js_copy(J, 2);
652
0
    js_pushundefined(J);
653
0
    js_pushlstring(J, s, n); /* arg 1: substring that matched */
654
0
    js_pushnumber(J, s - source); /* arg 2: offset within search string */
655
0
    js_copy(J, 0); /* arg 3: search string */
656
0
    js_call(J, 3);
657
0
    r = js_tostring(J, -1);
658
0
    js_putm(J, &sb, source, s);
659
0
    js_puts(J, &sb, r);
660
0
    js_puts(J, &sb, s + n);
661
0
    js_putc(J, &sb, 0);
662
0
    js_pop(J, 1);
663
0
  } else {
664
0
    r = js_tostring(J, 2);
665
0
    js_putm(J, &sb, source, s);
666
0
    while (*r) {
667
0
      if (*r == '$') {
668
0
        switch (*(++r)) {
669
0
        case 0: --r; /* end of string; back up */
670
        /* fallthrough */
671
0
        case '$': js_putc(J, &sb, '$'); break;
672
0
        case '&': js_putm(J, &sb, s, s + n); break;
673
0
        case '`': js_putm(J, &sb, source, s); break;
674
0
        case '\'': js_puts(J, &sb, s + n); break;
675
0
        default: js_putc(J, &sb, '$'); js_putc(J, &sb, *r); break;
676
0
        }
677
0
        ++r;
678
0
      } else {
679
0
        js_putc(J, &sb, *r++);
680
0
      }
681
0
    }
682
0
    js_puts(J, &sb, s + n);
683
0
    js_putc(J, &sb, 0);
684
0
  }
685
686
0
  if (js_try(J)) {
687
0
    js_free(J, sb);
688
0
    js_throw(J);
689
0
  }
690
0
  js_pushstring(J, sb ? sb->s : "");
691
0
  js_endtry(J);
692
0
  js_free(J, sb);
693
0
}
694
695
static void Sp_replace(js_State *J)
696
0
{
697
0
  if (js_isregexp(J, 1))
698
0
    Sp_replace_regexp(J);
699
0
  else
700
0
    Sp_replace_string(J);
701
0
}
702
703
static void Sp_split_regexp(js_State *J)
704
0
{
705
0
  js_Regexp *re;
706
0
  const char *text;
707
0
  int limit, len, k;
708
0
  const char *p, *a, *b, *c, *e;
709
0
  Resub m;
710
711
0
  text = checkstring(J, 0);
712
0
  re = js_toregexp(J, 1);
713
0
  limit = js_isdefined(J, 2) ? js_tointeger(J, 2) : 1 << 30;
714
715
0
  js_newarray(J);
716
0
  len = 0;
717
718
0
  if (limit == 0)
719
0
    return;
720
721
0
  e = text + strlen(text);
722
723
  /* splitting the empty string */
724
0
  if (e == text) {
725
0
    if (js_doregexec(J, re->prog, text, &m, 0)) {
726
0
      js_pushliteral(J, "");
727
0
      js_setindex(J, -2, 0);
728
0
    }
729
0
    return;
730
0
  }
731
732
0
  p = a = text;
733
0
  while (a < e) {
734
0
    if (js_doregexec(J, re->prog, a, &m, a > text ? REG_NOTBOL : 0))
735
0
      break; /* no match */
736
737
0
    b = m.sub[0].sp;
738
0
    c = m.sub[0].ep;
739
740
    /* empty string at end of last match */
741
0
    if (b == c && b == p) {
742
0
      ++a;
743
0
      continue;
744
0
    }
745
746
0
    if (len == limit) return;
747
0
    js_pushlstring(J, p, b - p);
748
0
    js_setindex(J, -2, len++);
749
750
0
    for (k = 1; k < m.nsub; ++k) {
751
0
      if (len == limit) return;
752
0
      js_pushlstring(J, m.sub[k].sp, m.sub[k].ep - m.sub[k].sp);
753
0
      js_setindex(J, -2, len++);
754
0
    }
755
756
0
    a = p = c;
757
0
  }
758
759
0
  if (len == limit) return;
760
0
  js_pushstring(J, p);
761
0
  js_setindex(J, -2, len);
762
0
}
763
764
static void Sp_split_string(js_State *J)
765
0
{
766
0
  const char *str = checkstring(J, 0);
767
0
  const char *sep = js_tostring(J, 1);
768
0
  int limit = js_isdefined(J, 2) ? js_tointeger(J, 2) : 1 << 30;
769
0
  int i, n;
770
771
0
  js_newarray(J);
772
773
0
  if (limit == 0)
774
0
    return;
775
776
0
  n = strlen(sep);
777
778
  /* empty string */
779
0
  if (n == 0) {
780
0
    Rune rune;
781
0
    for (i = 0; *str && i < limit; ++i) {
782
0
      n = chartorune(&rune, str);
783
0
      js_pushlstring(J, str, n);
784
0
      js_setindex(J, -2, i);
785
0
      str += n;
786
0
    }
787
0
    return;
788
0
  }
789
790
0
  for (i = 0; str && i < limit; ++i) {
791
0
    const char *s = strstr(str, sep);
792
0
    if (s) {
793
0
      js_pushlstring(J, str, s-str);
794
0
      js_setindex(J, -2, i);
795
0
      str = s + n;
796
0
    } else {
797
0
      js_pushstring(J, str);
798
0
      js_setindex(J, -2, i);
799
0
      str = NULL;
800
0
    }
801
0
  }
802
0
}
803
804
static void Sp_split(js_State *J)
805
0
{
806
0
  if (js_isundefined(J, 1)) {
807
0
    js_newarray(J);
808
0
    js_pushstring(J, js_tostring(J, 0));
809
0
    js_setindex(J, -2, 0);
810
0
  } else if (js_isregexp(J, 1)) {
811
0
    Sp_split_regexp(J);
812
0
  } else {
813
0
    Sp_split_string(J);
814
0
  }
815
0
}
816
817
void jsB_initstring(js_State *J)
818
0
{
819
0
  J->String_prototype->u.s.shrstr[0] = 0;
820
0
  J->String_prototype->u.s.string = J->String_prototype->u.s.shrstr;
821
0
  J->String_prototype->u.s.length = 0;
822
823
0
  js_pushobject(J, J->String_prototype);
824
0
  {
825
0
    jsB_propf(J, "String.prototype.toString", Sp_toString, 0);
826
0
    jsB_propf(J, "String.prototype.valueOf", Sp_valueOf, 0);
827
0
    jsB_propf(J, "String.prototype.charAt", Sp_charAt, 1);
828
0
    jsB_propf(J, "String.prototype.charCodeAt", Sp_charCodeAt, 1);
829
0
    jsB_propf(J, "String.prototype.concat", Sp_concat, 0); /* 1 */
830
0
    jsB_propf(J, "String.prototype.indexOf", Sp_indexOf, 1);
831
0
    jsB_propf(J, "String.prototype.lastIndexOf", Sp_lastIndexOf, 1);
832
0
    jsB_propf(J, "String.prototype.localeCompare", Sp_localeCompare, 1);
833
0
    jsB_propf(J, "String.prototype.match", Sp_match, 1);
834
0
    jsB_propf(J, "String.prototype.replace", Sp_replace, 2);
835
0
    jsB_propf(J, "String.prototype.search", Sp_search, 1);
836
0
    jsB_propf(J, "String.prototype.slice", Sp_slice, 2);
837
0
    jsB_propf(J, "String.prototype.split", Sp_split, 2);
838
0
    jsB_propf(J, "String.prototype.substring", Sp_substring, 2);
839
0
    jsB_propf(J, "String.prototype.toLowerCase", Sp_toLowerCase, 0);
840
0
    jsB_propf(J, "String.prototype.toLocaleLowerCase", Sp_toLowerCase, 0);
841
0
    jsB_propf(J, "String.prototype.toUpperCase", Sp_toUpperCase, 0);
842
0
    jsB_propf(J, "String.prototype.toLocaleUpperCase", Sp_toUpperCase, 0);
843
844
    /* ES5 */
845
0
    jsB_propf(J, "String.prototype.trim", Sp_trim, 0);
846
0
  }
847
0
  js_newcconstructor(J, jsB_String, jsB_new_String, "String", 0); /* 1 */
848
0
  {
849
0
    jsB_propf(J, "String.fromCharCode", S_fromCharCode, 0); /* 1 */
850
0
  }
851
0
  js_defglobal(J, "String", JS_DONTENUM);
852
0
}