diff options
Diffstat (limited to 'src/lj_str.c')
-rw-r--r-- | src/lj_str.c | 212 |
1 files changed, 35 insertions, 177 deletions
diff --git a/src/lj_str.c b/src/lj_str.c index 279c5cc3..ec74afa5 100644 --- a/src/lj_str.c +++ b/src/lj_str.c | |||
@@ -1,13 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | ** String handling. | 2 | ** String handling. |
3 | ** Copyright (C) 2005-2020 Mike Pall. See Copyright Notice in luajit.h | 3 | ** Copyright (C) 2005-2020 Mike Pall. See Copyright Notice in luajit.h |
4 | ** | ||
5 | ** 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 | */ | 4 | */ |
8 | 5 | ||
9 | #include <stdio.h> | ||
10 | |||
11 | #define lj_str_c | 6 | #define lj_str_c |
12 | #define LUA_CORE | 7 | #define LUA_CORE |
13 | 8 | ||
@@ -15,10 +10,9 @@ | |||
15 | #include "lj_gc.h" | 10 | #include "lj_gc.h" |
16 | #include "lj_err.h" | 11 | #include "lj_err.h" |
17 | #include "lj_str.h" | 12 | #include "lj_str.h" |
18 | #include "lj_state.h" | ||
19 | #include "lj_char.h" | 13 | #include "lj_char.h" |
20 | 14 | ||
21 | /* -- String interning ---------------------------------------------------- */ | 15 | /* -- String helpers ------------------------------------------------------ */ |
22 | 16 | ||
23 | /* Ordered compare of strings. Assumes string data is 4-byte aligned. */ | 17 | /* Ordered compare of strings. Assumes string data is 4-byte aligned. */ |
24 | int32_t LJ_FASTCALL lj_str_cmp(GCstr *a, GCstr *b) | 18 | int32_t LJ_FASTCALL lj_str_cmp(GCstr *a, GCstr *b) |
@@ -64,6 +58,40 @@ static LJ_AINLINE int str_fastcmp(const char *a, const char *b, MSize len) | |||
64 | return 0; | 58 | return 0; |
65 | } | 59 | } |
66 | 60 | ||
61 | /* Find fixed string p inside string s. */ | ||
62 | const char *lj_str_find(const char *s, const char *p, MSize slen, MSize plen) | ||
63 | { | ||
64 | if (plen <= slen) { | ||
65 | if (plen == 0) { | ||
66 | return s; | ||
67 | } else { | ||
68 | int c = *(const uint8_t *)p++; | ||
69 | plen--; slen -= plen; | ||
70 | while (slen) { | ||
71 | const char *q = (const char *)memchr(s, c, slen); | ||
72 | if (!q) break; | ||
73 | if (memcmp(q+1, p, plen) == 0) return q; | ||
74 | q++; slen -= (MSize)(q-s); s = q; | ||
75 | } | ||
76 | } | ||
77 | } | ||
78 | return NULL; | ||
79 | } | ||
80 | |||
81 | /* Check whether a string has a pattern matching character. */ | ||
82 | int lj_str_haspattern(GCstr *s) | ||
83 | { | ||
84 | const char *p = strdata(s), *q = p + s->len; | ||
85 | while (p < q) { | ||
86 | int c = *(const uint8_t *)p++; | ||
87 | if (lj_char_ispunct(c) && strchr("^$*+?.([%-", c)) | ||
88 | return 1; /* Found a pattern matching char. */ | ||
89 | } | ||
90 | return 0; /* No pattern matching chars found. */ | ||
91 | } | ||
92 | |||
93 | /* -- String interning ---------------------------------------------------- */ | ||
94 | |||
67 | /* Resize the string hash table (grow and shrink). */ | 95 | /* Resize the string hash table (grow and shrink). */ |
68 | void lj_str_resize(lua_State *L, MSize newmask) | 96 | void lj_str_resize(lua_State *L, MSize newmask) |
69 | { | 97 | { |
@@ -167,173 +195,3 @@ void LJ_FASTCALL lj_str_free(global_State *g, GCstr *s) | |||
167 | lj_mem_free(g, s, sizestring(s)); | 195 | lj_mem_free(g, s, sizestring(s)); |
168 | } | 196 | } |
169 | 197 | ||
170 | /* -- Type conversions ---------------------------------------------------- */ | ||
171 | |||
172 | /* Print number to buffer. Canonicalizes non-finite values. */ | ||
173 | size_t LJ_FASTCALL lj_str_bufnum(char *s, cTValue *o) | ||
174 | { | ||
175 | if (LJ_LIKELY((o->u32.hi << 1) < 0xffe00000)) { /* Finite? */ | ||
176 | lua_Number n = o->n; | ||
177 | #if __BIONIC__ | ||
178 | if (tvismzero(o)) { s[0] = '-'; s[1] = '0'; return 2; } | ||
179 | #endif | ||
180 | return (size_t)lua_number2str(s, n); | ||
181 | } else if (((o->u32.hi & 0x000fffff) | o->u32.lo) != 0) { | ||
182 | s[0] = 'n'; s[1] = 'a'; s[2] = 'n'; return 3; | ||
183 | } else if ((o->u32.hi & 0x80000000) == 0) { | ||
184 | s[0] = 'i'; s[1] = 'n'; s[2] = 'f'; return 3; | ||
185 | } else { | ||
186 | s[0] = '-'; s[1] = 'i'; s[2] = 'n'; s[3] = 'f'; return 4; | ||
187 | } | ||
188 | } | ||
189 | |||
190 | /* Print integer to buffer. Returns pointer to start. */ | ||
191 | char * LJ_FASTCALL lj_str_bufint(char *p, int32_t k) | ||
192 | { | ||
193 | uint32_t u = (uint32_t)(k < 0 ? -k : k); | ||
194 | p += 1+10; | ||
195 | do { *--p = (char)('0' + u % 10); } while (u /= 10); | ||
196 | if (k < 0) *--p = '-'; | ||
197 | return p; | ||
198 | } | ||
199 | |||
200 | /* Convert number to string. */ | ||
201 | GCstr * LJ_FASTCALL lj_str_fromnum(lua_State *L, const lua_Number *np) | ||
202 | { | ||
203 | char buf[LJ_STR_NUMBUF]; | ||
204 | size_t len = lj_str_bufnum(buf, (TValue *)np); | ||
205 | return lj_str_new(L, buf, len); | ||
206 | } | ||
207 | |||
208 | /* Convert integer to string. */ | ||
209 | GCstr * LJ_FASTCALL lj_str_fromint(lua_State *L, int32_t k) | ||
210 | { | ||
211 | char s[1+10]; | ||
212 | char *p = lj_str_bufint(s, k); | ||
213 | return lj_str_new(L, p, (size_t)(s+sizeof(s)-p)); | ||
214 | } | ||
215 | |||
216 | GCstr * LJ_FASTCALL lj_str_fromnumber(lua_State *L, cTValue *o) | ||
217 | { | ||
218 | return tvisint(o) ? lj_str_fromint(L, intV(o)) : lj_str_fromnum(L, &o->n); | ||
219 | } | ||
220 | |||
221 | /* -- String formatting --------------------------------------------------- */ | ||
222 | |||
223 | static void addstr(lua_State *L, SBuf *sb, const char *str, MSize len) | ||
224 | { | ||
225 | char *p; | ||
226 | MSize i; | ||
227 | if (sb->n + len > sb->sz) { | ||
228 | MSize sz = sb->sz * 2; | ||
229 | while (sb->n + len > sz) sz = sz * 2; | ||
230 | lj_str_resizebuf(L, sb, sz); | ||
231 | } | ||
232 | p = sb->buf + sb->n; | ||
233 | sb->n += len; | ||
234 | for (i = 0; i < len; i++) p[i] = str[i]; | ||
235 | } | ||
236 | |||
237 | static void addchar(lua_State *L, SBuf *sb, int c) | ||
238 | { | ||
239 | if (sb->n + 1 > sb->sz) { | ||
240 | MSize sz = sb->sz * 2; | ||
241 | lj_str_resizebuf(L, sb, sz); | ||
242 | } | ||
243 | sb->buf[sb->n++] = (char)c; | ||
244 | } | ||
245 | |||
246 | /* Push formatted message as a string object to Lua stack. va_list variant. */ | ||
247 | const char *lj_str_pushvf(lua_State *L, const char *fmt, va_list argp) | ||
248 | { | ||
249 | SBuf *sb = &G(L)->tmpbuf; | ||
250 | lj_str_needbuf(L, sb, (MSize)strlen(fmt)); | ||
251 | lj_str_resetbuf(sb); | ||
252 | for (;;) { | ||
253 | const char *e = strchr(fmt, '%'); | ||
254 | if (e == NULL) break; | ||
255 | addstr(L, sb, fmt, (MSize)(e-fmt)); | ||
256 | /* This function only handles %s, %c, %d, %f and %p formats. */ | ||
257 | switch (e[1]) { | ||
258 | case 's': { | ||
259 | const char *s = va_arg(argp, char *); | ||
260 | if (s == NULL) s = "(null)"; | ||
261 | addstr(L, sb, s, (MSize)strlen(s)); | ||
262 | break; | ||
263 | } | ||
264 | case 'c': | ||
265 | addchar(L, sb, va_arg(argp, int)); | ||
266 | break; | ||
267 | case 'd': { | ||
268 | char buf[LJ_STR_INTBUF]; | ||
269 | char *p = lj_str_bufint(buf, va_arg(argp, int32_t)); | ||
270 | addstr(L, sb, p, (MSize)(buf+LJ_STR_INTBUF-p)); | ||
271 | break; | ||
272 | } | ||
273 | case 'f': { | ||
274 | char buf[LJ_STR_NUMBUF]; | ||
275 | TValue tv; | ||
276 | MSize len; | ||
277 | tv.n = (lua_Number)(va_arg(argp, LUAI_UACNUMBER)); | ||
278 | len = (MSize)lj_str_bufnum(buf, &tv); | ||
279 | addstr(L, sb, buf, len); | ||
280 | break; | ||
281 | } | ||
282 | case 'p': { | ||
283 | #define FMTP_CHARS (2*sizeof(ptrdiff_t)) | ||
284 | char buf[2+FMTP_CHARS]; | ||
285 | ptrdiff_t p = (ptrdiff_t)(va_arg(argp, void *)); | ||
286 | ptrdiff_t i, lasti = 2+FMTP_CHARS; | ||
287 | if (p == 0) { | ||
288 | addstr(L, sb, "NULL", 4); | ||
289 | break; | ||
290 | } | ||
291 | #if LJ_64 | ||
292 | /* Shorten output for 64 bit pointers. */ | ||
293 | lasti = 2+2*4+((p >> 32) ? 2+2*(lj_fls((uint32_t)(p >> 32))>>3) : 0); | ||
294 | #endif | ||
295 | buf[0] = '0'; | ||
296 | buf[1] = 'x'; | ||
297 | for (i = lasti-1; i >= 2; i--, p >>= 4) | ||
298 | buf[i] = "0123456789abcdef"[(p & 15)]; | ||
299 | addstr(L, sb, buf, (MSize)lasti); | ||
300 | break; | ||
301 | } | ||
302 | case '%': | ||
303 | addchar(L, sb, '%'); | ||
304 | break; | ||
305 | default: | ||
306 | addchar(L, sb, '%'); | ||
307 | addchar(L, sb, e[1]); | ||
308 | break; | ||
309 | } | ||
310 | fmt = e+2; | ||
311 | } | ||
312 | addstr(L, sb, fmt, (MSize)strlen(fmt)); | ||
313 | setstrV(L, L->top, lj_str_new(L, sb->buf, sb->n)); | ||
314 | incr_top(L); | ||
315 | return strVdata(L->top - 1); | ||
316 | } | ||
317 | |||
318 | /* Push formatted message as a string object to Lua stack. Vararg variant. */ | ||
319 | const char *lj_str_pushf(lua_State *L, const char *fmt, ...) | ||
320 | { | ||
321 | const char *msg; | ||
322 | va_list argp; | ||
323 | va_start(argp, fmt); | ||
324 | msg = lj_str_pushvf(L, fmt, argp); | ||
325 | va_end(argp); | ||
326 | return msg; | ||
327 | } | ||
328 | |||
329 | /* -- Buffer handling ----------------------------------------------------- */ | ||
330 | |||
331 | char *lj_str_needbuf(lua_State *L, SBuf *sb, MSize sz) | ||
332 | { | ||
333 | if (sz > sb->sz) { | ||
334 | if (sz < LJ_MIN_SBUF) sz = LJ_MIN_SBUF; | ||
335 | lj_str_resizebuf(L, sb, sz); | ||
336 | } | ||
337 | return sb->buf; | ||
338 | } | ||
339 | |||