• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tarantool / luajit / 11774765987

11 Nov 2024 08:22AM UTC coverage: 92.931% (-0.008%) from 92.939%
11774765987

push

github

mandesero
tmp commit for ci check

5694 of 6033 branches covered (94.38%)

Branch coverage included in aggregate %.

21704 of 23449 relevant lines covered (92.56%)

2961521.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.31
/src/lib_string.c
1
/*
2
** String library.
3
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
4
**
5
** Major portions taken verbatim or adapted from the Lua interpreter.
6
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
7
*/
8

9
#define lib_string_c
10
#define LUA_LIB
11

12
#include "lua.h"
13
#include "lauxlib.h"
14
#include "lualib.h"
15

16
#include "lj_obj.h"
17
#include "lj_gc.h"
18
#include "lj_err.h"
19
#include "lj_buf.h"
20
#include "lj_str.h"
21
#include "lj_tab.h"
22
#include "lj_meta.h"
23
#include "lj_state.h"
24
#include "lj_ff.h"
25
#include "lj_bcdump.h"
26
#include "lj_char.h"
27
#include "lj_strfmt.h"
28
#include "lj_lib.h"
29

30
/* ------------------------------------------------------------------------ */
31

32
#define LJLIB_MODULE_string
33

34
LJLIB_LUA(string_len) /*
35
  function(s)
36
    CHECK_str(s)
37
    return #s
38
  end
39
*/
40

41
LJLIB_ASM(string_byte)                LJLIB_REC(string_range 0)
1,941✔
42
{
43
  GCstr *s = lj_lib_checkstr(L, 1);
1,941✔
44
  int32_t len = (int32_t)s->len;
1,941✔
45
  int32_t start = lj_lib_optint(L, 2, 1);
1,941✔
46
  int32_t stop = lj_lib_optint(L, 3, start);
1,941✔
47
  int32_t n, i;
1,941✔
48
  const unsigned char *p;
1,941✔
49
  if (stop < 0) stop += len+1;
1,941✔
50
  if (start < 0) start += len+1;
1,941✔
51
  if (start <= 0) start = 1;
1,941✔
52
  if (stop > len) stop = len;
1,941✔
53
  if (start > stop) return FFH_RES(0);  /* Empty interval: return no results. */
1,941✔
54
  start--;
1,664✔
55
  n = stop - start;
1,664✔
56
  if ((uint32_t)n > LUAI_MAXCSTACK)
1,664✔
57
    lj_err_caller(L, LJ_ERR_STRSLC);
×
58
  lj_state_checkstack(L, (MSize)n);
1,664✔
59
  p = (const unsigned char *)strdata(s) + start;
1,664✔
60
  for (i = 0; i < n; i++)
84,302✔
61
    setintV(L->base + i-1-LJ_FR2, p[i]);
82,638✔
62
  return FFH_RES(n);
1,664✔
63
}
64

65
LJLIB_ASM(string_char)                LJLIB_REC(.)
646✔
66
{
67
  int i, nargs = (int)(L->top - L->base);
646✔
68
  char *buf = lj_buf_tmp(L, (MSize)nargs);
646✔
69
  for (i = 1; i <= nargs; i++) {
3,147✔
70
    int32_t k = lj_lib_checkint(L, i);
1,858✔
71
    if (!checku8(k))
1,857✔
72
      lj_err_arg(L, i, LJ_ERR_BADVAL);
2✔
73
    buf[i-1] = (char)k;
1,855✔
74
  }
75
  setstrV(L, L->base-1-LJ_FR2, lj_str_new(L, buf, (size_t)nargs));
643✔
76
  return FFH_RES(1);
643✔
77
}
78

79
LJLIB_ASM(string_sub)                LJLIB_REC(string_range 1)
2✔
80
{
81
  lj_lib_checkstr(L, 1);
2✔
82
  lj_lib_checkint(L, 2);
2✔
83
  setintV(L->base+2, lj_lib_optint(L, 3, -1));
×
84
  return FFH_RETRY;
×
85
}
86

87
LJLIB_CF(string_rep)                LJLIB_REC(.)
2,137✔
88
{
89
  GCstr *s = lj_lib_checkstr(L, 1);
2,137✔
90
  int32_t rep = lj_lib_checkint(L, 2);
2,137✔
91
  GCstr *sep = lj_lib_optstr(L, 3);
2,137✔
92
  SBuf *sb = lj_buf_tmp_(L);
2,137✔
93
  if (sep && rep > 1) {
2,137✔
94
    GCstr *s2 = lj_buf_cat2str(L, sep, s);
37✔
95
    lj_buf_reset(sb);
37✔
96
    lj_buf_putstr(sb, s);
37✔
97
    s = s2;
37✔
98
    rep--;
37✔
99
  }
100
  sb = lj_buf_putstr_rep(sb, s, rep);
2,137✔
101
  setstrV(L, L->top-1, lj_buf_str(L, sb));
2,136✔
102
  lj_gc_check(L);
2,136✔
103
  return 1;
2,136✔
104
}
105

106
LJLIB_ASM(string_reverse)  LJLIB_REC(string_op IRCALL_lj_buf_putstr_reverse)
174✔
107
{
108
  lj_lib_checkstr(L, 1);
174✔
109
  return FFH_RETRY;
174✔
110
}
111
LJLIB_ASM_(string_lower)  LJLIB_REC(string_op IRCALL_lj_buf_putstr_lower)
112
LJLIB_ASM_(string_upper)  LJLIB_REC(string_op IRCALL_lj_buf_putstr_upper)
113

114
/* ------------------------------------------------------------------------ */
115

116
static int writer_buf(lua_State *L, const void *p, size_t size, void *sb)
480✔
117
{
118
  lj_buf_putmem((SBuf *)sb, p, (MSize)size);
480✔
119
  UNUSED(L);
480✔
120
  return 0;
480✔
121
}
122

123
LJLIB_CF(string_dump)
52✔
124
{
125
  GCfunc *fn = lj_lib_checkfunc(L, 1);
52✔
126
  int strip = L->base+1 < L->top && tvistruecond(L->base+1);
52✔
127
  SBuf *sb = lj_buf_tmp_(L);  /* Assumes lj_bcwrite() doesn't use tmpbuf. */
52✔
128
  L->top = L->base+1;
52✔
129
  if (!isluafunc(fn) || lj_bcwrite(L, funcproto(fn), writer_buf, sb, strip))
52✔
130
    lj_err_caller(L, LJ_ERR_STRDUMP);
1✔
131
  setstrV(L, L->top-1, lj_buf_str(L, sb));
51✔
132
  lj_gc_check(L);
51✔
133
  return 1;
51✔
134
}
135

136
/* ------------------------------------------------------------------------ */
137

138
/* macro to `unsign' a character */
139
#define uchar(c)        ((unsigned char)(c))
140

141
#define CAP_UNFINISHED        (-1)
142
#define CAP_POSITION        (-2)
143

144
typedef struct MatchState {
145
  const char *src_init;  /* init of source string */
146
  const char *src_end;  /* end (`\0') of source string */
147
  lua_State *L;
148
  int level;  /* total number of captures (finished or unfinished) */
149
  int depth;
150
  struct {
151
    const char *init;
152
    ptrdiff_t len;
153
  } capture[LUA_MAXCAPTURES];
154
} MatchState;
155

156
#define L_ESC                '%'
157

158
static int check_capture(MatchState *ms, int l)
97✔
159
{
160
  l -= '1';
97✔
161
  if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
97✔
162
    lj_err_caller(ms->L, LJ_ERR_STRCAPI);
3✔
163
  return l;
94✔
164
}
165

166
static int capture_to_close(MatchState *ms)
14,448✔
167
{
168
  int level = ms->level;
14,448✔
169
  for (level--; level>=0; level--)
14,469✔
170
    if (ms->capture[level].len == CAP_UNFINISHED) return level;
14,467✔
171
  lj_err_caller(ms->L, LJ_ERR_STRPATC);
2✔
172
  return 0;  /* unreachable */
173
}
174

175
static const char *classend(MatchState *ms, const char *p)
176
{
177
  switch (*p++) {
178
  case L_ESC:
179
    if (*p == '\0')
180
      lj_err_caller(ms->L, LJ_ERR_STRPATE);
181
    return p+1;
182
  case '[':
183
    if (*p == '^') p++;
184
    do {  /* look for a `]' */
185
      if (*p == '\0')
186
        lj_err_caller(ms->L, LJ_ERR_STRPATM);
187
      if (*(p++) == L_ESC && *p != '\0')
188
        p++;  /* skip escapes (e.g. `%]') */
189
    } while (*p != ']');
190
    return p+1;
191
  default:
192
    return p;
193
  }
194
}
195

196
static const unsigned char match_class_map[32] = {
197
  0,LJ_CHAR_ALPHA,0,LJ_CHAR_CNTRL,LJ_CHAR_DIGIT,0,0,LJ_CHAR_GRAPH,0,0,0,0,
198
  LJ_CHAR_LOWER,0,0,0,LJ_CHAR_PUNCT,0,0,LJ_CHAR_SPACE,0,
199
  LJ_CHAR_UPPER,0,LJ_CHAR_ALNUM,LJ_CHAR_XDIGIT,0,0,0,0,0,0,0
200
};
201

202
static int match_class(int c, int cl)
671,346✔
203
{
204
  if ((cl & 0xc0) == 0x40) {
671,346✔
205
    int t = match_class_map[(cl&0x1f)];
664,505✔
206
    if (t) {
664,505✔
207
      t = lj_char_isa(c, t);
663,320✔
208
      return (cl & 0x20) ? t : !t;
663,320✔
209
    }
210
    if (cl == 'z') return c == 0;
1,185✔
211
    if (cl == 'Z') return c != 0;
1,181✔
212
  }
213
  return (cl == c);
7,758✔
214
}
215

216
static int matchbracketclass(int c, const char *p, const char *ec)
162,058✔
217
{
218
  int sig = 1;
162,058✔
219
  if (*(p+1) == '^') {
162,058✔
220
    sig = 0;
155,167✔
221
    p++;  /* skip the `^' */
155,167✔
222
  }
223
  while (++p < ec) {
343,244✔
224
    if (*p == L_ESC) {
200,459✔
225
      p++;
4,548✔
226
      if (match_class(c, uchar(*p)))
4,548✔
227
        return sig;
228
    }
229
    else if ((*(p+1) == '-') && (p+2 < ec)) {
195,911✔
230
      p+=2;
1,911✔
231
      if (uchar(*(p-2)) <= c && c <= uchar(*p))
1,911✔
232
        return sig;
233
    }
234
    else if (uchar(*p) == c) return sig;
194,000✔
235
  }
236
  return !sig;
142,785✔
237
}
238

239
static int singlematch(int c, const char *p, const char *ep)
4,232,063✔
240
{
241
  switch (*p) {
4,232,063✔
242
  case '.': return 1;  /* matches any char */
243
  case L_ESC: return match_class(c, uchar(*(p+1)));
666,798✔
244
  case '[': return matchbracketclass(c, p, ep-1);
161,852✔
245
  default:  return (uchar(*p) == c);
2,791,019✔
246
  }
247
}
248

249
static const char *match(MatchState *ms, const char *s, const char *p);
250

251
static const char *matchbalance(MatchState *ms, const char *s, const char *p)
252
{
253
  if (*p == 0 || *(p+1) == 0)
254
    lj_err_caller(ms->L, LJ_ERR_STRPATU);
255
  if (*s != *p) {
256
    return NULL;
257
  } else {
258
    int b = *p;
259
    int e = *(p+1);
260
    int cont = 1;
261
    while (++s < ms->src_end) {
262
      if (*s == e) {
263
        if (--cont == 0) return s+1;
264
      } else if (*s == b) {
265
        cont++;
266
      }
267
    }
268
  }
269
  return NULL;  /* string ends out of balance */
270
}
271

272
static const char *max_expand(MatchState *ms, const char *s,
117,323✔
273
                              const char *p, const char *ep)
274
{
275
  ptrdiff_t i = 0;  /* counts maximum expand for item */
117,323✔
276
  while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep))
866,230✔
277
    i++;
748,907✔
278
  /* keeps trying to match with the maximum repetitions */
279
  while (i>=0) {
598,952✔
280
    const char *res = match(ms, (s+i), ep+1);
491,621✔
281
    if (res) return res;
491,621✔
282
    i--;  /* else didn't match; reduce 1 repetition to try again */
481,629✔
283
  }
284
  return NULL;
285
}
286

287
static const char *min_expand(MatchState *ms, const char *s,
90✔
288
                              const char *p, const char *ep)
289
{
290
  for (;;) {
602,060✔
291
    const char *res = match(ms, s, ep+1);
301,075✔
292
    if (res != NULL)
301,075✔
293
      return res;
87✔
294
    else if (s<ms->src_end && singlematch(uchar(*s), p, ep))
300,988✔
295
      s++;  /* try with one more repetition */
300,985✔
296
    else
297
      return NULL;
298
  }
299
}
300

301
static const char *start_capture(MatchState *ms, const char *s,
562,043✔
302
                                 const char *p, int what)
303
{
304
  const char *res;
562,043✔
305
  int level = ms->level;
562,043✔
306
  if (level >= LUA_MAXCAPTURES) lj_err_caller(ms->L, LJ_ERR_STRCAPN);
562,043✔
307
  ms->capture[level].init = s;
562,043✔
308
  ms->capture[level].len = what;
562,043✔
309
  ms->level = level+1;
562,043✔
310
  if ((res=match(ms, s, p)) == NULL)  /* match failed? */
562,043✔
311
    ms->level--;  /* undo capture */
548,363✔
312
  return res;
562,041✔
313
}
314

315
static const char *end_capture(MatchState *ms, const char *s,
14,448✔
316
                               const char *p)
317
{
318
  int l = capture_to_close(ms);
14,448✔
319
  const char *res;
14,446✔
320
  ms->capture[l].len = s - ms->capture[l].init;  /* close capture */
14,446✔
321
  if ((res = match(ms, s, p)) == NULL)  /* match failed? */
14,446✔
322
    ms->capture[l].len = CAP_UNFINISHED;  /* undo capture */
1,660✔
323
  return res;
14,446✔
324
}
325

326
static const char *match_capture(MatchState *ms, const char *s, int l)
97✔
327
{
328
  size_t len;
97✔
329
  l = check_capture(ms, l);
97✔
330
  len = (size_t)ms->capture[l].len;
94✔
331
  if ((size_t)(ms->src_end-s) >= len &&
94✔
332
      memcmp(ms->capture[l].init, s, len) == 0)
65✔
333
    return s+len;
22✔
334
  else
335
    return NULL;
336
}
337

338
static const char *match(MatchState *ms, const char *s, const char *p)
3,767,540✔
339
{
340
  if (++ms->depth > LJ_MAX_XLEVEL)
3,767,540✔
341
    lj_err_caller(ms->L, LJ_ERR_STRPATX);
×
342
  init: /* using goto's to optimize tail recursion */
3,767,540✔
343
  switch (*p) {
4,491,726✔
344
  case '(':  /* start capture */
562,043✔
345
    if (*(p+1) == ')')  /* position capture? */
562,043✔
346
      s = start_capture(ms, s, p+2, CAP_POSITION);
269,475✔
347
    else
348
      s = start_capture(ms, s, p+1, CAP_UNFINISHED);
292,568✔
349
    break;
350
  case ')':  /* end capture */
14,448✔
351
    s = end_capture(ms, s, p+1);
14,448✔
352
    break;
14,448✔
353
  case L_ESC:
559,524✔
354
    switch (*(p+1)) {
559,524✔
355
    case 'b':  /* balanced string? */
53✔
356
      s = matchbalance(ms, s, p+2);
53✔
357
      if (s == NULL) break;
52✔
358
      p+=4;
12✔
359
      goto init;  /* else s = match(ms, s, p+4); */
12✔
360
    case 'f': {  /* frontier? */
144✔
361
      const char *ep; char previous;
144✔
362
      p += 2;
144✔
363
      if (*p != '[')
144✔
364
        lj_err_caller(ms->L, LJ_ERR_STRPATB);
1✔
365
      ep = classend(ms, p);  /* points to what is next */
143✔
366
      previous = (s == ms->src_init) ? '\0' : *(s-1);
143✔
367
      if (matchbracketclass(uchar(previous), p, ep-1) ||
206✔
368
         !matchbracketclass(uchar(*s), p, ep-1)) { s = NULL; break; }
63✔
369
      p=ep;
34✔
370
      goto init;  /* else s = match(ms, s, ep); */
34✔
371
      }
372
    default:
559,327✔
373
      if (lj_char_isdigit(uchar(*(p+1)))) {  /* capture results (%0-%9)? */
559,327✔
374
        s = match_capture(ms, s, uchar(*(p+1)));
97✔
375
        if (s == NULL) break;
94✔
376
        p+=2;
22✔
377
        goto init;  /* else s = match(ms, s, p+2) */
22✔
378
      }
379
      goto dflt;  /* case default */
559,230✔
380
    }
381
    break;
112✔
382
  case '\0':  /* end of pattern */
383
    break;  /* match succeeded */
384
  case '$':
777,647✔
385
    /* is the `$' the last char in pattern? */
386
    if (*(p+1) != '\0') goto dflt;
777,647✔
387
    if (s != ms->src_end) s = NULL;  /* check end of string */
777,495✔
388
    break;
389
  default: dflt: {  /* it is a pattern item */
3,090,465✔
390
    const char *ep = classend(ms, p);  /* points to what is next */
3,090,465✔
391
    int m = s<ms->src_end && singlematch(uchar(*s), p, ep);
3,090,461✔
392
    switch (*ep) {
3,090,461✔
393
    case '?': {  /* optional */
600,149✔
394
      const char *res;
600,149✔
395
      if (m && ((res=match(ms, s+1, ep+1)) != NULL)) {
600,149✔
396
        s = res;
397
        break;
398
      }
399
      p=ep+1;
600,068✔
400
      goto init;  /* else s = match(ms, s, ep+1); */
600,068✔
401
      }
402
    case '*':  /* 0 or more repetitions */
5,441✔
403
      s = max_expand(ms, s, p, ep);
5,441✔
404
      break;
5,441✔
405
    case '+':  /* 1 or more repetitions */
557,157✔
406
      s = (m ? max_expand(ms, s+1, p, ep) : NULL);
557,157✔
407
      break;
408
    case '-':  /* 0 or more repetitions (minimum) */
90✔
409
      s = min_expand(ms, s, p, ep);
90✔
410
      break;
90✔
411
    default:
1,927,624✔
412
      if (m) { s++; p=ep; goto init; }  /* else s = match(ms, s+1, ep); */
1,927,624✔
413
      s = NULL;
414
      break;
415
    }
416
    break;
417
    }
418
  }
419
  ms->depth--;
3,767,527✔
420
  return s;
3,767,527✔
421
}
422

423
static void push_onecapture(MatchState *ms, int i, const char *s, const char *e)
15,772✔
424
{
425
  if (i >= ms->level) {
15,772✔
426
    if (i == 0)  /* ms->level == 0, too */
2,105✔
427
      lua_pushlstring(ms->L, s, (size_t)(e - s));  /* add whole match */
2,103✔
428
    else
429
      lj_err_caller(ms->L, LJ_ERR_STRCAPI);
2✔
430
  } else {
431
    ptrdiff_t l = ms->capture[i].len;
13,667✔
432
    if (l == CAP_UNFINISHED) lj_err_caller(ms->L, LJ_ERR_STRCAPU);
13,667✔
433
    if (l == CAP_POSITION)
13,665✔
434
      lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
890✔
435
    else
436
      lua_pushlstring(ms->L, ms->capture[i].init, (size_t)l);
12,775✔
437
  }
438
}
15,768✔
439

440
static int push_captures(MatchState *ms, const char *s, const char *e)
13,710✔
441
{
442
  int i;
13,710✔
443
  int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
13,710✔
444
  luaL_checkstack(ms->L, nlevels, "too many captures");
13,710✔
445
  for (i = 0; i < nlevels; i++)
43,004✔
446
    push_onecapture(ms, i, s, e);
15,585✔
447
  return nlevels;  /* number of strings pushed */
13,709✔
448
}
449

450
static int str_find_aux(lua_State *L, int find)
4,671✔
451
{
452
  GCstr *s = lj_lib_checkstr(L, 1);
4,671✔
453
  GCstr *p = lj_lib_checkstr(L, 2);
4,671✔
454
  int32_t start = lj_lib_optint(L, 3, 1);
4,671✔
455
  MSize st;
4,671✔
456
  if (start < 0) start += (int32_t)s->len; else start--;
4,671✔
457
  if (start < 0) start = 0;
4,671✔
458
  st = (MSize)start;
4,671✔
459
  if (st > s->len) {
4,671✔
460
#if LJ_52
461
    setnilV(L->top-1);
462
    return 1;
463
#else
464
    st = s->len;
465
#endif
466
  }
467
  if (find && ((L->base+3 < L->top && tvistruecond(L->base+3)) ||
7,314✔
468
               !lj_str_haspattern(p))) {  /* Search for fixed string. */
2,643✔
469
    const char *q = lj_str_find(strdata(s)+st, strdata(p), s->len-st, p->len);
1,425✔
470
    if (q) {
1,425✔
471
      setintV(L->top-2, (int32_t)(q-strdata(s)) + 1);
236✔
472
      setintV(L->top-1, (int32_t)(q-strdata(s)) + (int32_t)p->len);
236✔
473
      return 2;
236✔
474
    }
475
  } else {  /* Search for pattern. */
476
    MatchState ms;
3,246✔
477
    const char *pstr = strdata(p);
3,246✔
478
    const char *sstr = strdata(s) + st;
3,246✔
479
    int anchor = 0;
3,246✔
480
    if (*pstr == '^') { pstr++; anchor = 1; }
3,246✔
481
    ms.L = L;
3,246✔
482
    ms.src_init = strdata(s);
3,246✔
483
    ms.src_end = strdata(s) + s->len;
3,246✔
484
    do {  /* Loop through string and try to match the pattern. */
69,895✔
485
      const char *q;
69,895✔
486
      ms.level = ms.depth = 0;
69,895✔
487
      q = match(&ms, sstr, pstr);
69,895✔
488
      if (q) {
69,888✔
489
        if (find) {
1,162✔
490
          setintV(L->top++, (int32_t)(sstr-(strdata(s)-1)));
253✔
491
          setintV(L->top++, (int32_t)(q-strdata(s)));
253✔
492
          return push_captures(&ms, NULL, NULL) + 2;
1,162✔
493
        } else {
494
          return push_captures(&ms, sstr, q);
909✔
495
        }
496
      }
497
    } while (sstr++ < ms.src_end && !anchor);
68,726✔
498
  }
499
  setnilV(L->top-1);  /* Not found. */
3,266✔
500
  return 1;
3,266✔
501
}
502

503
LJLIB_CF(string_find)                LJLIB_REC(.)
2,755✔
504
{
505
  return str_find_aux(L, 1);
2,755✔
506
}
507

508
LJLIB_CF(string_match)
1,916✔
509
{
510
  return str_find_aux(L, 0);
1,916✔
511
}
512

513
LJLIB_NOREG LJLIB_CF(string_gmatch_aux)
373✔
514
{
515
  const char *p = strVdata(lj_lib_upvalue(L, 2));
373✔
516
  GCstr *str = strV(lj_lib_upvalue(L, 1));
373✔
517
  const char *s = strdata(str);
373✔
518
  TValue *tvpos = lj_lib_upvalue(L, 3);
373✔
519
  const char *src = s + tvpos->u32.lo;
373✔
520
  MatchState ms;
373✔
521
  ms.L = L;
373✔
522
  ms.src_init = s;
373✔
523
  ms.src_end = s + str->len;
373✔
524
  for (; src <= ms.src_end; src++) {
6,841✔
525
    const char *e;
6,748✔
526
    ms.level = ms.depth = 0;
6,748✔
527
    if ((e = match(&ms, src, p)) != NULL) {
6,748✔
528
      int32_t pos = (int32_t)(e - s);
280✔
529
      if (e == src) pos++;  /* Ensure progress for empty match. */
280✔
530
      tvpos->u32.lo = (uint32_t)pos;
280✔
531
      return push_captures(&ms, src, e);
280✔
532
    }
533
  }
534
  return 0;  /* not found */
535
}
536

537
LJLIB_CF(string_gmatch)
101✔
538
{
539
  lj_lib_checkstr(L, 1);
101✔
540
  lj_lib_checkstr(L, 2);
101✔
541
  L->top = L->base+3;
101✔
542
  (L->top-1)->u64 = 0;
101✔
543
  lj_lib_pushcc(L, lj_cf_string_gmatch_aux, FF_string_gmatch_aux, 3);
101✔
544
  return 1;
101✔
545
}
546

547
static void add_s(MatchState *ms, luaL_Buffer *b, const char *s, const char *e)
33,726✔
548
{
549
  size_t l, i;
33,726✔
550
  const char *news = lua_tolstring(ms->L, 3, &l);
33,726✔
551
  for (i = 0; i < l; i++) {
69,533✔
552
    if (news[i] != L_ESC) {
2,083✔
553
      luaL_addchar(b, news[i]);
1,963✔
554
    } else {
555
      i++;  /* skip ESC */
120✔
556
      if (!lj_char_isdigit(uchar(news[i]))) {
120✔
557
        luaL_addchar(b, news[i]);
19✔
558
      } else if (news[i] == '0') {
101✔
559
        luaL_addlstring(b, s, (size_t)(e - s));
25✔
560
      } else {
561
        push_onecapture(ms, news[i] - '1', s, e);
76✔
562
        luaL_addvalue(b);  /* add capture to accumulated result */
74✔
563
      }
564
    }
565
  }
566
}
33,724✔
567

568
static void add_value(MatchState *ms, luaL_Buffer *b,
46,105✔
569
                      const char *s, const char *e)
570
{
571
  lua_State *L = ms->L;
46,105✔
572
  switch (lua_type(L, 3)) {
46,105✔
573
    case LUA_TNUMBER:
33,726✔
574
    case LUA_TSTRING: {
575
      add_s(ms, b, s, e);
33,726✔
576
      return;
33,726✔
577
    }
578
    case LUA_TFUNCTION: {
12,268✔
579
      int n;
12,268✔
580
      lua_pushvalue(L, 3);
12,268✔
581
      n = push_captures(ms, s, e);
12,268✔
582
      lua_call(L, n, 1);
12,267✔
583
      break;
12,267✔
584
    }
585
    case LUA_TTABLE: {
111✔
586
      push_onecapture(ms, 0, s, e);
111✔
587
      lua_gettable(L, 3);
110✔
588
      break;
110✔
589
    }
590
  }
591
  if (!lua_toboolean(L, -1)) {  /* nil or false? */
12,377✔
592
    lua_pop(L, 1);
1,297✔
593
    lua_pushlstring(L, s, (size_t)(e - s));  /* keep original text */
1,297✔
594
  } else if (!lua_isstring(L, -1)) {
11,080✔
595
    lj_err_callerv(L, LJ_ERR_STRGSRV, luaL_typename(L, -1));
1✔
596
  }
597
  luaL_addvalue(b);  /* add result to accumulator */
12,376✔
598
}
599

600
LJLIB_CF(string_gsub)
22,498✔
601
{
602
  size_t srcl;
22,498✔
603
  const char *src = luaL_checklstring(L, 1, &srcl);
22,498✔
604
  const char *p = luaL_checkstring(L, 2);
22,498✔
605
  int  tr = lua_type(L, 3);
22,498✔
606
  int max_s = luaL_optint(L, 4, (int)(srcl+1));
22,498✔
607
  int anchor = (*p == '^') ? (p++, 1) : 0;
22,498✔
608
  int n = 0;
22,498✔
609
  MatchState ms;
22,498✔
610
  luaL_Buffer b;
22,498✔
611
  if (!(tr == LUA_TNUMBER || tr == LUA_TSTRING ||
30✔
612
        tr == LUA_TFUNCTION || tr == LUA_TTABLE))
22,498✔
613
    lj_err_arg(L, 3, LJ_ERR_NOSFT);
1✔
614
  luaL_buffinit(L, &b);
22,497✔
615
  ms.L = L;
22,497✔
616
  ms.src_init = src;
22,497✔
617
  ms.src_end = src+srcl;
22,497✔
618
  while (n < max_s) {
1,721,653✔
619
    const char *e;
1,721,630✔
620
    ms.level = ms.depth = 0;
1,721,630✔
621
    e = match(&ms, src, p);
1,721,630✔
622
    if (e) {
1,721,626✔
623
      n++;
46,105✔
624
      add_value(&ms, &b, src, e);
46,105✔
625
    }
626
    if (e && e>src) /* non empty match? */
1,721,621✔
627
      src = e;  /* skip it */
628
    else if (src < ms.src_end)
1,675,542✔
629
      luaL_addchar(&b, *src++);
1,653,114✔
630
    else
631
      break;
632
    if (anchor)
1,699,193✔
633
      break;
634
  }
635
  luaL_addlstring(&b, src, (size_t)(ms.src_end-src));
22,488✔
636
  luaL_pushresult(&b);
22,488✔
637
  lua_pushinteger(L, n);  /* number of substitutions */
22,488✔
638
  return 2;
22,488✔
639
}
640

641
/* ------------------------------------------------------------------------ */
642

643
/* Emulate tostring() inline. */
644
static GCstr *string_fmt_tostring(lua_State *L, int arg, int retry)
138,442✔
645
{
646
  TValue *o = L->base+arg-1;
138,442✔
647
  cTValue *mo;
138,442✔
648
  lj_assertL(o < L->top, "bad usage");  /* Caller already checks for existence. */
138,442✔
649
  if (LJ_LIKELY(tvisstr(o)))
138,442✔
650
    return strV(o);
135,665✔
651
  if (retry != 2 && !tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
2,777✔
652
    copyTV(L, L->top++, mo);
×
653
    copyTV(L, L->top++, o);
×
654
    lua_call(L, 1, 1);
×
655
    copyTV(L, L->base+arg-1, --L->top);
×
656
    return NULL;  /* Buffer may be overwritten, retry. */
×
657
  }
658
  return lj_strfmt_obj(L, o);
2,777✔
659
}
660

661
LJLIB_CF(string_format)                LJLIB_REC(.)
29,361✔
662
{
663
  int arg, top = (int)(L->top - L->base);
29,361✔
664
  GCstr *fmt;
29,361✔
665
  SBuf *sb;
29,361✔
666
  FormatState fs;
29,361✔
667
  SFormat sf;
29,361✔
668
  int retry = 0;
29,361✔
669
again:
29,361✔
670
  arg = 1;
29,361✔
671
  sb = lj_buf_tmp_(L);
29,361✔
672
  fmt = lj_lib_checkstr(L, arg);
29,361✔
673
  lj_strfmt_init(&fs, strdata(fmt), fmt->len);
29,361✔
674
  while ((sf = lj_strfmt_parse(&fs)) != STRFMT_EOF) {
444,098✔
675
    if (sf == STRFMT_LIT) {
414,743✔
676
      lj_buf_putmem(sb, fs.str, fs.len);
266,290✔
677
    } else if (sf == STRFMT_ERR) {
148,453✔
678
      lj_err_callerv(L, LJ_ERR_STRFMT, strdata(lj_str_new(L, fs.str, fs.len)));
4✔
679
    } else {
680
      if (++arg > top)
148,449✔
681
        luaL_argerror(L, arg, lj_obj_typename[0]);
1✔
682
      switch (STRFMT_TYPE(sf)) {
148,448✔
683
      case STRFMT_INT:
684
        if (tvisint(L->base+arg-1)) {
8,723✔
685
          int32_t k = intV(L->base+arg-1);
686
          if (sf == STRFMT_INT)
687
            lj_strfmt_putint(sb, k);  /* Shortcut for plain %d. */
688
          else
689
            lj_strfmt_putfxint(sb, sf, k);
690
        } else {
691
          lj_strfmt_putfnum_int(sb, sf, lj_lib_checknum(L, arg));
8,723✔
692
        }
693
        break;
8,722✔
694
      case STRFMT_UINT:
695
        if (tvisint(L->base+arg-1))
191✔
696
          lj_strfmt_putfxint(sb, sf, intV(L->base+arg-1));
697
        else
698
          lj_strfmt_putfnum_uint(sb, sf, lj_lib_checknum(L, arg));
191✔
699
        break;
191✔
700
      case STRFMT_NUM:
1,078✔
701
        lj_strfmt_putfnum(sb, sf, lj_lib_checknum(L, arg));
1,078✔
702
        break;
1,078✔
703
      case STRFMT_STR: {
138,442✔
704
        GCstr *str = string_fmt_tostring(L, arg, retry);
138,442✔
705
        if (str == NULL)
138,442✔
706
          retry = 1;
707
        else if ((sf & STRFMT_T_QUOTED))
138,442✔
708
          lj_strfmt_putquoted(sb, str);  /* No formatting. */
118✔
709
        else
710
          lj_strfmt_putfstr(sb, sf, str);
138,324✔
711
        break;
712
        }
713
      case STRFMT_CHAR:
12✔
714
        lj_strfmt_putfchar(sb, sf, lj_lib_checkint(L, arg));
12✔
715
        break;
12✔
716
      case STRFMT_PTR:  /* No formatting. */
2✔
717
        lj_strfmt_putptr(sb, lj_obj_ptr(G(L), L->base+arg-1));
2✔
718
        break;
2✔
719
      default:
720
        lj_assertL(0, "bad string format type");
721
        break;
722
      }
723
    }
724
  }
725
  if (retry++ == 1) goto again;
29,355✔
726
  setstrV(L, L->top-1, lj_buf_str(L, sb));
29,355✔
727
  lj_gc_check(L);
29,355✔
728
  return 1;
29,355✔
729
}
730

731
/* ------------------------------------------------------------------------ */
732

733
#include "lj_libdef.h"
734

735
LUALIB_API int luaopen_string(lua_State *L)
350✔
736
{
737
  GCtab *mt;
350✔
738
  global_State *g;
350✔
739
  LJ_LIB_REG(L, LUA_STRLIBNAME, string);
350✔
740
  mt = lj_tab_new(L, 0, 1);
350✔
741
  /* NOBARRIER: basemt is a GC root. */
742
  g = G(L);
350✔
743
  setgcref(basemt_it(g, LJ_TSTR), obj2gco(mt));
350✔
744
  settabV(L, lj_tab_setstr(L, mt, mmname_str(g, MM_index)), tabV(L->top-1));
350✔
745
  mt->nomm = (uint8_t)(~(1u<<MM_index));
350✔
746
  return 1;
350✔
747
}
748

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc