aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/luajit-2.0/src/lib_string.c
diff options
context:
space:
mode:
authorDavid Walter Seikel2012-01-23 23:36:30 +1000
committerDavid Walter Seikel2012-01-23 23:36:30 +1000
commit6523585c66c04cea54df50013df8886b589847d8 (patch)
tree0b22aee7064166d88595eda260ca2d17c0773da5 /libraries/luajit-2.0/src/lib_string.c
parentUpdate the EFL to what I'm actually using, coz I'm using some stuff not yet r... (diff)
downloadSledjHamr-6523585c66c04cea54df50013df8886b589847d8.zip
SledjHamr-6523585c66c04cea54df50013df8886b589847d8.tar.gz
SledjHamr-6523585c66c04cea54df50013df8886b589847d8.tar.bz2
SledjHamr-6523585c66c04cea54df50013df8886b589847d8.tar.xz
Add luaproc and LuaJIT libraries.
Two versions of LuaJIT, the stable release, and the dev version. Try the dev version first, until ih fails badly.
Diffstat (limited to 'libraries/luajit-2.0/src/lib_string.c')
-rw-r--r--libraries/luajit-2.0/src/lib_string.c855
1 files changed, 855 insertions, 0 deletions
diff --git a/libraries/luajit-2.0/src/lib_string.c b/libraries/luajit-2.0/src/lib_string.c
new file mode 100644
index 0000000..5cbe6e4
--- /dev/null
+++ b/libraries/luajit-2.0/src/lib_string.c
@@ -0,0 +1,855 @@
1/*
2** String library.
3** Copyright (C) 2005-2011 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#include <stdio.h>
10
11#define lib_string_c
12#define LUA_LIB
13
14#include "lua.h"
15#include "lauxlib.h"
16#include "lualib.h"
17
18#include "lj_obj.h"
19#include "lj_gc.h"
20#include "lj_err.h"
21#include "lj_str.h"
22#include "lj_tab.h"
23#include "lj_state.h"
24#include "lj_ff.h"
25#include "lj_bcdump.h"
26#include "lj_char.h"
27#include "lj_lib.h"
28
29/* ------------------------------------------------------------------------ */
30
31#define LJLIB_MODULE_string
32
33LJLIB_ASM(string_len) LJLIB_REC(.)
34{
35 lj_lib_checkstr(L, 1);
36 return FFH_RETRY;
37}
38
39LJLIB_ASM(string_byte) LJLIB_REC(string_range 0)
40{
41 GCstr *s = lj_lib_checkstr(L, 1);
42 int32_t len = (int32_t)s->len;
43 int32_t start = lj_lib_optint(L, 2, 1);
44 int32_t stop = lj_lib_optint(L, 3, start);
45 int32_t n, i;
46 const unsigned char *p;
47 if (stop < 0) stop += len+1;
48 if (start < 0) start += len+1;
49 if (start <= 0) start = 1;
50 if (stop > len) stop = len;
51 if (start > stop) return FFH_RES(0); /* Empty interval: return no results. */
52 start--;
53 n = stop - start;
54 if ((uint32_t)n > LUAI_MAXCSTACK)
55 lj_err_caller(L, LJ_ERR_STRSLC);
56 lj_state_checkstack(L, (MSize)n);
57 p = (const unsigned char *)strdata(s) + start;
58 for (i = 0; i < n; i++)
59 setintV(L->base + i-1, p[i]);
60 return FFH_RES(n);
61}
62
63LJLIB_ASM(string_char)
64{
65 int i, nargs = (int)(L->top - L->base);
66 char *buf = lj_str_needbuf(L, &G(L)->tmpbuf, (size_t)nargs);
67 for (i = 1; i <= nargs; i++) {
68 int32_t k = lj_lib_checkint(L, i);
69 if (!checku8(k))
70 lj_err_arg(L, i, LJ_ERR_BADVAL);
71 buf[i-1] = (char)k;
72 }
73 setstrV(L, L->base-1, lj_str_new(L, buf, (size_t)nargs));
74 return FFH_RES(1);
75}
76
77LJLIB_ASM(string_sub) LJLIB_REC(string_range 1)
78{
79 lj_lib_checkstr(L, 1);
80 lj_lib_checkint(L, 2);
81 setintV(L->base+2, lj_lib_optint(L, 3, -1));
82 return FFH_RETRY;
83}
84
85LJLIB_ASM(string_rep)
86{
87 GCstr *s = lj_lib_checkstr(L, 1);
88 int32_t len = (int32_t)s->len;
89 int32_t k = lj_lib_checkint(L, 2);
90 int64_t tlen = (int64_t)k * len;
91 const char *src;
92 char *buf;
93 if (k <= 0) return FFH_RETRY;
94 if (tlen > LJ_MAX_STR)
95 lj_err_caller(L, LJ_ERR_STROV);
96 buf = lj_str_needbuf(L, &G(L)->tmpbuf, (MSize)tlen);
97 if (len <= 1) return FFH_RETRY; /* ASM code only needed buffer resize. */
98 src = strdata(s);
99 do {
100 int32_t i = 0;
101 do { *buf++ = src[i++]; } while (i < len);
102 } while (--k > 0);
103 setstrV(L, L->base-1, lj_str_new(L, G(L)->tmpbuf.buf, (size_t)tlen));
104 return FFH_RES(1);
105}
106
107LJLIB_ASM(string_reverse)
108{
109 GCstr *s = lj_lib_checkstr(L, 1);
110 lj_str_needbuf(L, &G(L)->tmpbuf, s->len);
111 return FFH_RETRY;
112}
113LJLIB_ASM_(string_lower)
114LJLIB_ASM_(string_upper)
115
116/* ------------------------------------------------------------------------ */
117
118static int writer_buf(lua_State *L, const void *p, size_t size, void *b)
119{
120 luaL_addlstring((luaL_Buffer *)b, (const char *)p, size);
121 UNUSED(L);
122 return 0;
123}
124
125LJLIB_CF(string_dump)
126{
127 GCfunc *fn = lj_lib_checkfunc(L, 1);
128 int strip = L->base+1 < L->top && tvistruecond(L->base+1);
129 luaL_Buffer b;
130 L->top = L->base+1;
131 luaL_buffinit(L, &b);
132 if (!isluafunc(fn) || lj_bcwrite(L, funcproto(fn), writer_buf, &b, strip))
133 lj_err_caller(L, LJ_ERR_STRDUMP);
134 luaL_pushresult(&b);
135 return 1;
136}
137
138/* ------------------------------------------------------------------------ */
139
140/* macro to `unsign' a character */
141#define uchar(c) ((unsigned char)(c))
142
143#define CAP_UNFINISHED (-1)
144#define CAP_POSITION (-2)
145
146typedef struct MatchState {
147 const char *src_init; /* init of source string */
148 const char *src_end; /* end (`\0') of source string */
149 lua_State *L;
150 int level; /* total number of captures (finished or unfinished) */
151 struct {
152 const char *init;
153 ptrdiff_t len;
154 } capture[LUA_MAXCAPTURES];
155} MatchState;
156
157#define L_ESC '%'
158#define SPECIALS "^$*+?.([%-"
159
160static int check_capture(MatchState *ms, int l)
161{
162 l -= '1';
163 if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
164 lj_err_caller(ms->L, LJ_ERR_STRCAPI);
165 return l;
166}
167
168static int capture_to_close(MatchState *ms)
169{
170 int level = ms->level;
171 for (level--; level>=0; level--)
172 if (ms->capture[level].len == CAP_UNFINISHED) return level;
173 lj_err_caller(ms->L, LJ_ERR_STRPATC);
174 return 0; /* unreachable */
175}
176
177static const char *classend(MatchState *ms, const char *p)
178{
179 switch (*p++) {
180 case L_ESC:
181 if (*p == '\0')
182 lj_err_caller(ms->L, LJ_ERR_STRPATE);
183 return p+1;
184 case '[':
185 if (*p == '^') p++;
186 do { /* look for a `]' */
187 if (*p == '\0')
188 lj_err_caller(ms->L, LJ_ERR_STRPATM);
189 if (*(p++) == L_ESC && *p != '\0')
190 p++; /* skip escapes (e.g. `%]') */
191 } while (*p != ']');
192 return p+1;
193 default:
194 return p;
195 }
196}
197
198static const unsigned char match_class_map[32] = {
199 0,LJ_CHAR_ALPHA,0,LJ_CHAR_CNTRL,LJ_CHAR_DIGIT,0,0,LJ_CHAR_GRAPH,0,0,0,0,
200 LJ_CHAR_LOWER,0,0,0,LJ_CHAR_PUNCT,0,0,LJ_CHAR_SPACE,0,
201 LJ_CHAR_UPPER,0,LJ_CHAR_ALNUM,LJ_CHAR_XDIGIT,0,0,0,0,0,0,0
202};
203
204static int match_class(int c, int cl)
205{
206 if ((cl & 0xc0) == 0x40) {
207 int t = match_class_map[(cl&0x1f)];
208 if (t) {
209 t = lj_char_isa(c, t);
210 return (cl & 0x20) ? t : !t;
211 }
212 if (cl == 'z') return c == 0;
213 if (cl == 'Z') return c != 0;
214 }
215 return (cl == c);
216}
217
218static int matchbracketclass(int c, const char *p, const char *ec)
219{
220 int sig = 1;
221 if (*(p+1) == '^') {
222 sig = 0;
223 p++; /* skip the `^' */
224 }
225 while (++p < ec) {
226 if (*p == L_ESC) {
227 p++;
228 if (match_class(c, uchar(*p)))
229 return sig;
230 }
231 else if ((*(p+1) == '-') && (p+2 < ec)) {
232 p+=2;
233 if (uchar(*(p-2)) <= c && c <= uchar(*p))
234 return sig;
235 }
236 else if (uchar(*p) == c) return sig;
237 }
238 return !sig;
239}
240
241static int singlematch(int c, const char *p, const char *ep)
242{
243 switch (*p) {
244 case '.': return 1; /* matches any char */
245 case L_ESC: return match_class(c, uchar(*(p+1)));
246 case '[': return matchbracketclass(c, p, ep-1);
247 default: return (uchar(*p) == c);
248 }
249}
250
251static const char *match(MatchState *ms, const char *s, const char *p);
252
253static const char *matchbalance(MatchState *ms, const char *s, const char *p)
254{
255 if (*p == 0 || *(p+1) == 0)
256 lj_err_caller(ms->L, LJ_ERR_STRPATU);
257 if (*s != *p) {
258 return NULL;
259 } else {
260 int b = *p;
261 int e = *(p+1);
262 int cont = 1;
263 while (++s < ms->src_end) {
264 if (*s == e) {
265 if (--cont == 0) return s+1;
266 } else if (*s == b) {
267 cont++;
268 }
269 }
270 }
271 return NULL; /* string ends out of balance */
272}
273
274static const char *max_expand(MatchState *ms, const char *s,
275 const char *p, const char *ep)
276{
277 ptrdiff_t i = 0; /* counts maximum expand for item */
278 while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep))
279 i++;
280 /* keeps trying to match with the maximum repetitions */
281 while (i>=0) {
282 const char *res = match(ms, (s+i), ep+1);
283 if (res) return res;
284 i--; /* else didn't match; reduce 1 repetition to try again */
285 }
286 return NULL;
287}
288
289static const char *min_expand(MatchState *ms, const char *s,
290 const char *p, const char *ep)
291{
292 for (;;) {
293 const char *res = match(ms, s, ep+1);
294 if (res != NULL)
295 return res;
296 else if (s<ms->src_end && singlematch(uchar(*s), p, ep))
297 s++; /* try with one more repetition */
298 else
299 return NULL;
300 }
301}
302
303static const char *start_capture(MatchState *ms, const char *s,
304 const char *p, int what)
305{
306 const char *res;
307 int level = ms->level;
308 if (level >= LUA_MAXCAPTURES) lj_err_caller(ms->L, LJ_ERR_STRCAPN);
309 ms->capture[level].init = s;
310 ms->capture[level].len = what;
311 ms->level = level+1;
312 if ((res=match(ms, s, p)) == NULL) /* match failed? */
313 ms->level--; /* undo capture */
314 return res;
315}
316
317static const char *end_capture(MatchState *ms, const char *s,
318 const char *p)
319{
320 int l = capture_to_close(ms);
321 const char *res;
322 ms->capture[l].len = s - ms->capture[l].init; /* close capture */
323 if ((res = match(ms, s, p)) == NULL) /* match failed? */
324 ms->capture[l].len = CAP_UNFINISHED; /* undo capture */
325 return res;
326}
327
328static const char *match_capture(MatchState *ms, const char *s, int l)
329{
330 size_t len;
331 l = check_capture(ms, l);
332 len = (size_t)ms->capture[l].len;
333 if ((size_t)(ms->src_end-s) >= len &&
334 memcmp(ms->capture[l].init, s, len) == 0)
335 return s+len;
336 else
337 return NULL;
338}
339
340static const char *match(MatchState *ms, const char *s, const char *p)
341{
342 init: /* using goto's to optimize tail recursion */
343 switch (*p) {
344 case '(': /* start capture */
345 if (*(p+1) == ')') /* position capture? */
346 return start_capture(ms, s, p+2, CAP_POSITION);
347 else
348 return start_capture(ms, s, p+1, CAP_UNFINISHED);
349 case ')': /* end capture */
350 return end_capture(ms, s, p+1);
351 case L_ESC:
352 switch (*(p+1)) {
353 case 'b': /* balanced string? */
354 s = matchbalance(ms, s, p+2);
355 if (s == NULL) return NULL;
356 p+=4;
357 goto init; /* else return match(ms, s, p+4); */
358 case 'f': { /* frontier? */
359 const char *ep; char previous;
360 p += 2;
361 if (*p != '[')
362 lj_err_caller(ms->L, LJ_ERR_STRPATB);
363 ep = classend(ms, p); /* points to what is next */
364 previous = (s == ms->src_init) ? '\0' : *(s-1);
365 if (matchbracketclass(uchar(previous), p, ep-1) ||
366 !matchbracketclass(uchar(*s), p, ep-1)) return NULL;
367 p=ep;
368 goto init; /* else return match(ms, s, ep); */
369 }
370 default:
371 if (lj_char_isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */
372 s = match_capture(ms, s, uchar(*(p+1)));
373 if (s == NULL) return NULL;
374 p+=2;
375 goto init; /* else return match(ms, s, p+2) */
376 }
377 goto dflt; /* case default */
378 }
379 case '\0': /* end of pattern */
380 return s; /* match succeeded */
381 case '$':
382 if (*(p+1) == '\0') /* is the `$' the last char in pattern? */
383 return (s == ms->src_end) ? s : NULL; /* check end of string */
384 else
385 goto dflt;
386 default: dflt: { /* it is a pattern item */
387 const char *ep = classend(ms, p); /* points to what is next */
388 int m = s<ms->src_end && singlematch(uchar(*s), p, ep);
389 switch (*ep) {
390 case '?': { /* optional */
391 const char *res;
392 if (m && ((res=match(ms, s+1, ep+1)) != NULL))
393 return res;
394 p=ep+1;
395 goto init; /* else return match(ms, s, ep+1); */
396 }
397 case '*': /* 0 or more repetitions */
398 return max_expand(ms, s, p, ep);
399 case '+': /* 1 or more repetitions */
400 return (m ? max_expand(ms, s+1, p, ep) : NULL);
401 case '-': /* 0 or more repetitions (minimum) */
402 return min_expand(ms, s, p, ep);
403 default:
404 if (!m) return NULL;
405 s++; p=ep;
406 goto init; /* else return match(ms, s+1, ep); */
407 }
408 }
409 }
410}
411
412static const char *lmemfind(const char *s1, size_t l1,
413 const char *s2, size_t l2)
414{
415 if (l2 == 0) {
416 return s1; /* empty strings are everywhere */
417 } else if (l2 > l1) {
418 return NULL; /* avoids a negative `l1' */
419 } else {
420 const char *init; /* to search for a `*s2' inside `s1' */
421 l2--; /* 1st char will be checked by `memchr' */
422 l1 = l1-l2; /* `s2' cannot be found after that */
423 while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
424 init++; /* 1st char is already checked */
425 if (memcmp(init, s2+1, l2) == 0) {
426 return init-1;
427 } else { /* correct `l1' and `s1' to try again */
428 l1 -= (size_t)(init-s1);
429 s1 = init;
430 }
431 }
432 return NULL; /* not found */
433 }
434}
435
436static void push_onecapture(MatchState *ms, int i, const char *s, const char *e)
437{
438 if (i >= ms->level) {
439 if (i == 0) /* ms->level == 0, too */
440 lua_pushlstring(ms->L, s, (size_t)(e - s)); /* add whole match */
441 else
442 lj_err_caller(ms->L, LJ_ERR_STRCAPI);
443 } else {
444 ptrdiff_t l = ms->capture[i].len;
445 if (l == CAP_UNFINISHED) lj_err_caller(ms->L, LJ_ERR_STRCAPU);
446 if (l == CAP_POSITION)
447 lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
448 else
449 lua_pushlstring(ms->L, ms->capture[i].init, (size_t)l);
450 }
451}
452
453static int push_captures(MatchState *ms, const char *s, const char *e)
454{
455 int i;
456 int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
457 luaL_checkstack(ms->L, nlevels, "too many captures");
458 for (i = 0; i < nlevels; i++)
459 push_onecapture(ms, i, s, e);
460 return nlevels; /* number of strings pushed */
461}
462
463static ptrdiff_t posrelat(ptrdiff_t pos, size_t len)
464{
465 /* relative string position: negative means back from end */
466 if (pos < 0) pos += (ptrdiff_t)len + 1;
467 return (pos >= 0) ? pos : 0;
468}
469
470static int str_find_aux(lua_State *L, int find)
471{
472 size_t l1, l2;
473 const char *s = luaL_checklstring(L, 1, &l1);
474 const char *p = luaL_checklstring(L, 2, &l2);
475 ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1;
476 if (init < 0)
477 init = 0;
478 else if ((size_t)(init) > l1)
479 init = (ptrdiff_t)l1;
480 if (find && (lua_toboolean(L, 4) || /* explicit request? */
481 strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */
482 /* do a plain search */
483 const char *s2 = lmemfind(s+init, l1-(size_t)init, p, l2);
484 if (s2) {
485 lua_pushinteger(L, s2-s+1);
486 lua_pushinteger(L, s2-s+(ptrdiff_t)l2);
487 return 2;
488 }
489 } else {
490 MatchState ms;
491 int anchor = (*p == '^') ? (p++, 1) : 0;
492 const char *s1=s+init;
493 ms.L = L;
494 ms.src_init = s;
495 ms.src_end = s+l1;
496 do {
497 const char *res;
498 ms.level = 0;
499 if ((res=match(&ms, s1, p)) != NULL) {
500 if (find) {
501 lua_pushinteger(L, s1-s+1); /* start */
502 lua_pushinteger(L, res-s); /* end */
503 return push_captures(&ms, NULL, 0) + 2;
504 } else {
505 return push_captures(&ms, s1, res);
506 }
507 }
508 } while (s1++ < ms.src_end && !anchor);
509 }
510 lua_pushnil(L); /* not found */
511 return 1;
512}
513
514LJLIB_CF(string_find)
515{
516 return str_find_aux(L, 1);
517}
518
519LJLIB_CF(string_match)
520{
521 return str_find_aux(L, 0);
522}
523
524LJLIB_NOREG LJLIB_CF(string_gmatch_aux)
525{
526 const char *p = strVdata(lj_lib_upvalue(L, 2));
527 GCstr *str = strV(lj_lib_upvalue(L, 1));
528 const char *s = strdata(str);
529 TValue *tvpos = lj_lib_upvalue(L, 3);
530 const char *src = s + tvpos->u32.lo;
531 MatchState ms;
532 ms.L = L;
533 ms.src_init = s;
534 ms.src_end = s + str->len;
535 for (; src <= ms.src_end; src++) {
536 const char *e;
537 ms.level = 0;
538 if ((e = match(&ms, src, p)) != NULL) {
539 int32_t pos = (int32_t)(e - s);
540 if (e == src) pos++; /* Ensure progress for empty match. */
541 tvpos->u32.lo = (uint32_t)pos;
542 return push_captures(&ms, src, e);
543 }
544 }
545 return 0; /* not found */
546}
547
548LJLIB_CF(string_gmatch)
549{
550 lj_lib_checkstr(L, 1);
551 lj_lib_checkstr(L, 2);
552 L->top = L->base+3;
553 (L->top-1)->u64 = 0;
554 lj_lib_pushcc(L, lj_cf_string_gmatch_aux, FF_string_gmatch_aux, 3);
555 return 1;
556}
557
558static void add_s(MatchState *ms, luaL_Buffer *b, const char *s, const char *e)
559{
560 size_t l, i;
561 const char *news = lua_tolstring(ms->L, 3, &l);
562 for (i = 0; i < l; i++) {
563 if (news[i] != L_ESC) {
564 luaL_addchar(b, news[i]);
565 } else {
566 i++; /* skip ESC */
567 if (!lj_char_isdigit(uchar(news[i]))) {
568 luaL_addchar(b, news[i]);
569 } else if (news[i] == '0') {
570 luaL_addlstring(b, s, (size_t)(e - s));
571 } else {
572 push_onecapture(ms, news[i] - '1', s, e);
573 luaL_addvalue(b); /* add capture to accumulated result */
574 }
575 }
576 }
577}
578
579static void add_value(MatchState *ms, luaL_Buffer *b,
580 const char *s, const char *e)
581{
582 lua_State *L = ms->L;
583 switch (lua_type(L, 3)) {
584 case LUA_TNUMBER:
585 case LUA_TSTRING: {
586 add_s(ms, b, s, e);
587 return;
588 }
589 case LUA_TFUNCTION: {
590 int n;
591 lua_pushvalue(L, 3);
592 n = push_captures(ms, s, e);
593 lua_call(L, n, 1);
594 break;
595 }
596 case LUA_TTABLE: {
597 push_onecapture(ms, 0, s, e);
598 lua_gettable(L, 3);
599 break;
600 }
601 }
602 if (!lua_toboolean(L, -1)) { /* nil or false? */
603 lua_pop(L, 1);
604 lua_pushlstring(L, s, (size_t)(e - s)); /* keep original text */
605 } else if (!lua_isstring(L, -1)) {
606 lj_err_callerv(L, LJ_ERR_STRGSRV, luaL_typename(L, -1));
607 }
608 luaL_addvalue(b); /* add result to accumulator */
609}
610
611LJLIB_CF(string_gsub)
612{
613 size_t srcl;
614 const char *src = luaL_checklstring(L, 1, &srcl);
615 const char *p = luaL_checkstring(L, 2);
616 int tr = lua_type(L, 3);
617 int max_s = luaL_optint(L, 4, (int)(srcl+1));
618 int anchor = (*p == '^') ? (p++, 1) : 0;
619 int n = 0;
620 MatchState ms;
621 luaL_Buffer b;
622 if (!(tr == LUA_TNUMBER || tr == LUA_TSTRING ||
623 tr == LUA_TFUNCTION || tr == LUA_TTABLE))
624 lj_err_arg(L, 3, LJ_ERR_NOSFT);
625 luaL_buffinit(L, &b);
626 ms.L = L;
627 ms.src_init = src;
628 ms.src_end = src+srcl;
629 while (n < max_s) {
630 const char *e;
631 ms.level = 0;
632 e = match(&ms, src, p);
633 if (e) {
634 n++;
635 add_value(&ms, &b, src, e);
636 }
637 if (e && e>src) /* non empty match? */
638 src = e; /* skip it */
639 else if (src < ms.src_end)
640 luaL_addchar(&b, *src++);
641 else
642 break;
643 if (anchor)
644 break;
645 }
646 luaL_addlstring(&b, src, (size_t)(ms.src_end-src));
647 luaL_pushresult(&b);
648 lua_pushinteger(L, n); /* number of substitutions */
649 return 2;
650}
651
652/* ------------------------------------------------------------------------ */
653
654/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
655#define MAX_FMTITEM 512
656/* valid flags in a format specification */
657#define FMT_FLAGS "-+ #0"
658/*
659** maximum size of each format specification (such as '%-099.99d')
660** (+10 accounts for %99.99x plus margin of error)
661*/
662#define MAX_FMTSPEC (sizeof(FMT_FLAGS) + sizeof(LUA_INTFRMLEN) + 10)
663
664static void addquoted(lua_State *L, luaL_Buffer *b, int arg)
665{
666 GCstr *str = lj_lib_checkstr(L, arg);
667 int32_t len = (int32_t)str->len;
668 const char *s = strdata(str);
669 luaL_addchar(b, '"');
670 while (len--) {
671 if (*s == '"' || *s == '\\' || *s == '\n') {
672 luaL_addchar(b, '\\');
673 luaL_addchar(b, *s);
674 } else if (lj_char_iscntrl(uchar(*s))) {
675 uint32_t c1, c2, c3;
676 luaL_addchar(b, '\\');
677 c1 = uchar(*s); c3 = c1 % 10; c1 /= 10; c2 = c1 % 10; c1 /= 10;
678 if (c1 + lj_char_isdigit(uchar(s[1]))) luaL_addchar(b, '0' + c1);
679 if (c2 + (c1 + lj_char_isdigit(uchar(s[1])))) luaL_addchar(b, '0' + c2);
680 luaL_addchar(b, '0' + c3);
681 } else {
682 luaL_addchar(b, *s);
683 }
684 s++;
685 }
686 luaL_addchar(b, '"');
687}
688
689static const char *scanformat(lua_State *L, const char *strfrmt, char *form)
690{
691 const char *p = strfrmt;
692 while (*p != '\0' && strchr(FMT_FLAGS, *p) != NULL) p++; /* skip flags */
693 if ((size_t)(p - strfrmt) >= sizeof(FMT_FLAGS))
694 lj_err_caller(L, LJ_ERR_STRFMTR);
695 if (lj_char_isdigit(uchar(*p))) p++; /* skip width */
696 if (lj_char_isdigit(uchar(*p))) p++; /* (2 digits at most) */
697 if (*p == '.') {
698 p++;
699 if (lj_char_isdigit(uchar(*p))) p++; /* skip precision */
700 if (lj_char_isdigit(uchar(*p))) p++; /* (2 digits at most) */
701 }
702 if (lj_char_isdigit(uchar(*p)))
703 lj_err_caller(L, LJ_ERR_STRFMTW);
704 *(form++) = '%';
705 strncpy(form, strfrmt, (size_t)(p - strfrmt + 1));
706 form += p - strfrmt + 1;
707 *form = '\0';
708 return p;
709}
710
711static void addintlen(char *form)
712{
713 size_t l = strlen(form);
714 char spec = form[l - 1];
715 strcpy(form + l - 1, LUA_INTFRMLEN);
716 form[l + sizeof(LUA_INTFRMLEN) - 2] = spec;
717 form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0';
718}
719
720static unsigned LUA_INTFRM_T num2intfrm(lua_State *L, int arg)
721{
722 if (sizeof(LUA_INTFRM_T) == 4) {
723 return (LUA_INTFRM_T)lj_lib_checkbit(L, arg);
724 } else {
725 cTValue *o;
726 lj_lib_checknumber(L, arg);
727 o = L->base+arg-1;
728 if (tvisint(o))
729 return (LUA_INTFRM_T)intV(o);
730 else
731 return (LUA_INTFRM_T)numV(o);
732 }
733}
734
735static unsigned LUA_INTFRM_T num2uintfrm(lua_State *L, int arg)
736{
737 if (sizeof(LUA_INTFRM_T) == 4) {
738 return (unsigned LUA_INTFRM_T)lj_lib_checkbit(L, arg);
739 } else {
740 cTValue *o;
741 lj_lib_checknumber(L, arg);
742 o = L->base+arg-1;
743 if (tvisint(o))
744 return (unsigned LUA_INTFRM_T)intV(o);
745 else if ((int32_t)o->u32.hi < 0)
746 return (unsigned LUA_INTFRM_T)(LUA_INTFRM_T)numV(o);
747 else
748 return (unsigned LUA_INTFRM_T)numV(o);
749 }
750}
751
752LJLIB_CF(string_format)
753{
754 int arg = 1, top = (int)(L->top - L->base);
755 GCstr *fmt = lj_lib_checkstr(L, arg);
756 const char *strfrmt = strdata(fmt);
757 const char *strfrmt_end = strfrmt + fmt->len;
758 luaL_Buffer b;
759 luaL_buffinit(L, &b);
760 while (strfrmt < strfrmt_end) {
761 if (*strfrmt != L_ESC) {
762 luaL_addchar(&b, *strfrmt++);
763 } else if (*++strfrmt == L_ESC) {
764 luaL_addchar(&b, *strfrmt++); /* %% */
765 } else { /* format item */
766 char form[MAX_FMTSPEC]; /* to store the format (`%...') */
767 char buff[MAX_FMTITEM]; /* to store the formatted item */
768 if (++arg > top)
769 luaL_argerror(L, arg, lj_obj_typename[0]);
770 strfrmt = scanformat(L, strfrmt, form);
771 switch (*strfrmt++) {
772 case 'c':
773 sprintf(buff, form, lj_lib_checkint(L, arg));
774 break;
775 case 'd': case 'i':
776 addintlen(form);
777 sprintf(buff, form, num2intfrm(L, arg));
778 break;
779 case 'o': case 'u': case 'x': case 'X':
780 addintlen(form);
781 sprintf(buff, form, num2uintfrm(L, arg));
782 break;
783 case 'e': case 'E': case 'f': case 'g': case 'G': {
784 TValue tv;
785 tv.n = lj_lib_checknum(L, arg);
786 if (LJ_UNLIKELY((tv.u32.hi << 1) >= 0xffe00000)) {
787 /* Canonicalize output of non-finite values. */
788 char *p, nbuf[LJ_STR_NUMBUF];
789 size_t len = lj_str_bufnum(nbuf, &tv);
790 if (strfrmt[-1] == 'E' || strfrmt[-1] == 'G') {
791 nbuf[len-3] = nbuf[len-3] - 0x20;
792 nbuf[len-2] = nbuf[len-2] - 0x20;
793 nbuf[len-1] = nbuf[len-1] - 0x20;
794 }
795 nbuf[len] = '\0';
796 for (p = form; *p < 'e' && *p != '.'; p++) ;
797 *p++ = 's'; *p = '\0';
798 sprintf(buff, form, nbuf);
799 break;
800 }
801 sprintf(buff, form, (double)tv.n);
802 break;
803 }
804 case 'q':
805 addquoted(L, &b, arg);
806 continue;
807 case 'p':
808 lj_str_pushf(L, "%p", lua_topointer(L, arg));
809 luaL_addvalue(&b);
810 continue;
811 case 's': {
812 GCstr *str = lj_lib_checkstr(L, arg);
813 if (!strchr(form, '.') && str->len >= 100) {
814 /* no precision and string is too long to be formatted;
815 keep original string */
816 setstrV(L, L->top++, str);
817 luaL_addvalue(&b);
818 continue;
819 }
820 sprintf(buff, form, strdata(str));
821 break;
822 }
823 default:
824 lj_err_callerv(L, LJ_ERR_STRFMTO, *(strfrmt -1));
825 break;
826 }
827 luaL_addlstring(&b, buff, strlen(buff));
828 }
829 }
830 luaL_pushresult(&b);
831 return 1;
832}
833
834/* ------------------------------------------------------------------------ */
835
836#include "lj_libdef.h"
837
838LUALIB_API int luaopen_string(lua_State *L)
839{
840 GCtab *mt;
841 global_State *g;
842 LJ_LIB_REG(L, LUA_STRLIBNAME, string);
843#if defined(LUA_COMPAT_GFIND)
844 lua_getfield(L, -1, "gmatch");
845 lua_setfield(L, -2, "gfind");
846#endif
847 mt = lj_tab_new(L, 0, 1);
848 /* NOBARRIER: basemt is a GC root. */
849 g = G(L);
850 setgcref(basemt_it(g, LJ_TSTR), obj2gco(mt));
851 settabV(L, lj_tab_setstr(L, mt, mmname_str(g, MM_index)), tabV(L->top-1));
852 mt->nomm = (uint8_t)(~(1u<<MM_index));
853 return 1;
854}
855