]> git.proxmox.com Git - mirror_edk2.git/blame - AppPkg/Applications/Lua/src/lstrlib.c
EmbeddedPkg: Extend NvVarStoreFormattedLib LIBRARY_CLASS
[mirror_edk2.git] / AppPkg / Applications / Lua / src / lstrlib.c
CommitLineData
16a5fed6 1/*\r
2** $Id: lstrlib.c,v 1.178.1.1 2013/04/12 18:48:47 roberto Exp $\r
3** Standard library for string operations and pattern-matching\r
4** See Copyright Notice in lua.h\r
5*/\r
6\r
7\r
8#include <ctype.h>\r
9#include <stddef.h>\r
10#include <stdio.h>\r
11#include <stdlib.h>\r
12#include <string.h>\r
13\r
14#define lstrlib_c\r
15#define LUA_LIB\r
16\r
17#include "lua.h"\r
18\r
19#include "lauxlib.h"\r
20#include "lualib.h"\r
21\r
22\r
23/*\r
24** maximum number of captures that a pattern can do during\r
25** pattern-matching. This limit is arbitrary.\r
26*/\r
27#if !defined(LUA_MAXCAPTURES)\r
28#define LUA_MAXCAPTURES 32\r
29#endif\r
30\r
31\r
32/* macro to `unsign' a character */\r
33#define uchar(c) ((unsigned char)(c))\r
34\r
35\r
36\r
37static int str_len (lua_State *L) {\r
38 size_t l;\r
39 luaL_checklstring(L, 1, &l);\r
40 lua_pushinteger(L, (lua_Integer)l);\r
41 return 1;\r
42}\r
43\r
44\r
45/* translate a relative string position: negative means back from end */\r
46static size_t posrelat (ptrdiff_t pos, size_t len) {\r
47 if (pos >= 0) return (size_t)pos;\r
48 else if (0u - (size_t)pos > len) return 0;\r
49 else return len - ((size_t)-pos) + 1;\r
50}\r
51\r
52\r
53static int str_sub (lua_State *L) {\r
54 size_t l;\r
55 const char *s = luaL_checklstring(L, 1, &l);\r
56 size_t start = posrelat(luaL_checkinteger(L, 2), l);\r
57 size_t end = posrelat(luaL_optinteger(L, 3, -1), l);\r
58 if (start < 1) start = 1;\r
59 if (end > l) end = l;\r
60 if (start <= end)\r
61 lua_pushlstring(L, s + start - 1, end - start + 1);\r
62 else lua_pushliteral(L, "");\r
63 return 1;\r
64}\r
65\r
66\r
67static int str_reverse (lua_State *L) {\r
68 size_t l, i;\r
69 luaL_Buffer b;\r
70 const char *s = luaL_checklstring(L, 1, &l);\r
71 char *p = luaL_buffinitsize(L, &b, l);\r
72 for (i = 0; i < l; i++)\r
73 p[i] = s[l - i - 1];\r
74 luaL_pushresultsize(&b, l);\r
75 return 1;\r
76}\r
77\r
78\r
79static int str_lower (lua_State *L) {\r
80 size_t l;\r
81 size_t i;\r
82 luaL_Buffer b;\r
83 const char *s = luaL_checklstring(L, 1, &l);\r
84 char *p = luaL_buffinitsize(L, &b, l);\r
85 for (i=0; i<l; i++)\r
86 p[i] = tolower(uchar(s[i]));\r
87 luaL_pushresultsize(&b, l);\r
88 return 1;\r
89}\r
90\r
91\r
92static int str_upper (lua_State *L) {\r
93 size_t l;\r
94 size_t i;\r
95 luaL_Buffer b;\r
96 const char *s = luaL_checklstring(L, 1, &l);\r
97 char *p = luaL_buffinitsize(L, &b, l);\r
98 for (i=0; i<l; i++)\r
99 p[i] = toupper(uchar(s[i]));\r
100 luaL_pushresultsize(&b, l);\r
101 return 1;\r
102}\r
103\r
104\r
105/* reasonable limit to avoid arithmetic overflow */\r
106#define MAXSIZE ((~(size_t)0) >> 1)\r
107\r
108static int str_rep (lua_State *L) {\r
109 size_t l, lsep;\r
110 const char *s = luaL_checklstring(L, 1, &l);\r
111 int n = luaL_checkint(L, 2);\r
112 const char *sep = luaL_optlstring(L, 3, "", &lsep);\r
113 if (n <= 0) lua_pushliteral(L, "");\r
114 else if (l + lsep < l || l + lsep >= MAXSIZE / n) /* may overflow? */\r
115 return luaL_error(L, "resulting string too large");\r
116 else {\r
117 size_t totallen = n * l + (n - 1) * lsep;\r
118 luaL_Buffer b;\r
119 char *p = luaL_buffinitsize(L, &b, totallen);\r
120 while (n-- > 1) { /* first n-1 copies (followed by separator) */\r
121 memcpy(p, s, l * sizeof(char)); p += l;\r
122 if (lsep > 0) { /* avoid empty 'memcpy' (may be expensive) */\r
123 memcpy(p, sep, lsep * sizeof(char)); p += lsep;\r
124 }\r
125 }\r
126 memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */\r
127 luaL_pushresultsize(&b, totallen);\r
128 }\r
129 return 1;\r
130}\r
131\r
132\r
133static int str_byte (lua_State *L) {\r
134 size_t l;\r
135 const char *s = luaL_checklstring(L, 1, &l);\r
136 size_t posi = posrelat(luaL_optinteger(L, 2, 1), l);\r
137 size_t pose = posrelat(luaL_optinteger(L, 3, posi), l);\r
138 int n, i;\r
139 if (posi < 1) posi = 1;\r
140 if (pose > l) pose = l;\r
141 if (posi > pose) return 0; /* empty interval; return no values */\r
142 n = (int)(pose - posi + 1);\r
143 if (posi + n <= pose) /* (size_t -> int) overflow? */\r
144 return luaL_error(L, "string slice too long");\r
145 luaL_checkstack(L, n, "string slice too long");\r
146 for (i=0; i<n; i++)\r
147 lua_pushinteger(L, uchar(s[posi+i-1]));\r
148 return n;\r
149}\r
150\r
151\r
152static int str_char (lua_State *L) {\r
153 int n = lua_gettop(L); /* number of arguments */\r
154 int i;\r
155 luaL_Buffer b;\r
156 char *p = luaL_buffinitsize(L, &b, n);\r
157 for (i=1; i<=n; i++) {\r
158 int c = luaL_checkint(L, i);\r
159 luaL_argcheck(L, uchar(c) == c, i, "value out of range");\r
160 p[i - 1] = uchar(c);\r
161 }\r
162 luaL_pushresultsize(&b, n);\r
163 return 1;\r
164}\r
165\r
166\r
167static int writer (lua_State *L, const void* b, size_t size, void* B) {\r
168 (void)L;\r
169 luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);\r
170 return 0;\r
171}\r
172\r
173\r
174static int str_dump (lua_State *L) {\r
175 luaL_Buffer b;\r
176 luaL_checktype(L, 1, LUA_TFUNCTION);\r
177 lua_settop(L, 1);\r
178 luaL_buffinit(L,&b);\r
179 if (lua_dump(L, writer, &b) != 0)\r
180 return luaL_error(L, "unable to dump given function");\r
181 luaL_pushresult(&b);\r
182 return 1;\r
183}\r
184\r
185\r
186\r
187/*\r
188** {======================================================\r
189** PATTERN MATCHING\r
190** =======================================================\r
191*/\r
192\r
193\r
194#define CAP_UNFINISHED (-1)\r
195#define CAP_POSITION (-2)\r
196\r
197\r
198typedef struct MatchState {\r
199 int matchdepth; /* control for recursive depth (to avoid C stack overflow) */\r
200 const char *src_init; /* init of source string */\r
201 const char *src_end; /* end ('\0') of source string */\r
202 const char *p_end; /* end ('\0') of pattern */\r
203 lua_State *L;\r
204 int level; /* total number of captures (finished or unfinished) */\r
205 struct {\r
206 const char *init;\r
207 ptrdiff_t len;\r
208 } capture[LUA_MAXCAPTURES];\r
209} MatchState;\r
210\r
211\r
212/* recursive function */\r
213static const char *match (MatchState *ms, const char *s, const char *p);\r
214\r
215\r
216/* maximum recursion depth for 'match' */\r
217#if !defined(MAXCCALLS)\r
218#define MAXCCALLS 200\r
219#endif\r
220\r
221\r
222#define L_ESC '%'\r
223#define SPECIALS "^$*+?.([%-"\r
224\r
225\r
226static int check_capture (MatchState *ms, int l) {\r
227 l -= '1';\r
228 if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)\r
229 return luaL_error(ms->L, "invalid capture index %%%d", l + 1);\r
230 return l;\r
231}\r
232\r
233\r
234static int capture_to_close (MatchState *ms) {\r
235 int level = ms->level;\r
236 for (level--; level>=0; level--)\r
237 if (ms->capture[level].len == CAP_UNFINISHED) return level;\r
238 return luaL_error(ms->L, "invalid pattern capture");\r
239}\r
240\r
241\r
242static const char *classend (MatchState *ms, const char *p) {\r
243 switch (*p++) {\r
244 case L_ESC: {\r
245 if (p == ms->p_end)\r
246 luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")");\r
247 return p+1;\r
248 }\r
249 case '[': {\r
250 if (*p == '^') p++;\r
251 do { /* look for a `]' */\r
252 if (p == ms->p_end)\r
253 luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")");\r
254 if (*(p++) == L_ESC && p < ms->p_end)\r
255 p++; /* skip escapes (e.g. `%]') */\r
256 } while (*p != ']');\r
257 return p+1;\r
258 }\r
259 default: {\r
260 return p;\r
261 }\r
262 }\r
263}\r
264\r
265\r
266static int match_class (int c, int cl) {\r
267 int res;\r
268 switch (tolower(cl)) {\r
269 case 'a' : res = isalpha(c); break;\r
270 case 'c' : res = iscntrl(c); break;\r
271 case 'd' : res = isdigit(c); break;\r
272 case 'g' : res = isgraph(c); break;\r
273 case 'l' : res = islower(c); break;\r
274 case 'p' : res = ispunct(c); break;\r
275 case 's' : res = isspace(c); break;\r
276 case 'u' : res = isupper(c); break;\r
277 case 'w' : res = isalnum(c); break;\r
278 case 'x' : res = isxdigit(c); break;\r
279 case 'z' : res = (c == 0); break; /* deprecated option */\r
280 default: return (cl == c);\r
281 }\r
282 return (islower(cl) ? res : !res);\r
283}\r
284\r
285\r
286static int matchbracketclass (int c, const char *p, const char *ec) {\r
287 int sig = 1;\r
288 if (*(p+1) == '^') {\r
289 sig = 0;\r
290 p++; /* skip the `^' */\r
291 }\r
292 while (++p < ec) {\r
293 if (*p == L_ESC) {\r
294 p++;\r
295 if (match_class(c, uchar(*p)))\r
296 return sig;\r
297 }\r
298 else if ((*(p+1) == '-') && (p+2 < ec)) {\r
299 p+=2;\r
300 if (uchar(*(p-2)) <= c && c <= uchar(*p))\r
301 return sig;\r
302 }\r
303 else if (uchar(*p) == c) return sig;\r
304 }\r
305 return !sig;\r
306}\r
307\r
308\r
309static int singlematch (MatchState *ms, const char *s, const char *p,\r
310 const char *ep) {\r
311 if (s >= ms->src_end)\r
312 return 0;\r
313 else {\r
314 int c = uchar(*s);\r
315 switch (*p) {\r
316 case '.': return 1; /* matches any char */\r
317 case L_ESC: return match_class(c, uchar(*(p+1)));\r
318 case '[': return matchbracketclass(c, p, ep-1);\r
319 default: return (uchar(*p) == c);\r
320 }\r
321 }\r
322}\r
323\r
324\r
325static const char *matchbalance (MatchState *ms, const char *s,\r
326 const char *p) {\r
327 if (p >= ms->p_end - 1)\r
328 luaL_error(ms->L, "malformed pattern "\r
329 "(missing arguments to " LUA_QL("%%b") ")");\r
330 if (*s != *p) return NULL;\r
331 else {\r
332 int b = *p;\r
333 int e = *(p+1);\r
334 int cont = 1;\r
335 while (++s < ms->src_end) {\r
336 if (*s == e) {\r
337 if (--cont == 0) return s+1;\r
338 }\r
339 else if (*s == b) cont++;\r
340 }\r
341 }\r
342 return NULL; /* string ends out of balance */\r
343}\r
344\r
345\r
346static const char *max_expand (MatchState *ms, const char *s,\r
347 const char *p, const char *ep) {\r
348 ptrdiff_t i = 0; /* counts maximum expand for item */\r
349 while (singlematch(ms, s + i, p, ep))\r
350 i++;\r
351 /* keeps trying to match with the maximum repetitions */\r
352 while (i>=0) {\r
353 const char *res = match(ms, (s+i), ep+1);\r
354 if (res) return res;\r
355 i--; /* else didn't match; reduce 1 repetition to try again */\r
356 }\r
357 return NULL;\r
358}\r
359\r
360\r
361static const char *min_expand (MatchState *ms, const char *s,\r
362 const char *p, const char *ep) {\r
363 for (;;) {\r
364 const char *res = match(ms, s, ep+1);\r
365 if (res != NULL)\r
366 return res;\r
367 else if (singlematch(ms, s, p, ep))\r
368 s++; /* try with one more repetition */\r
369 else return NULL;\r
370 }\r
371}\r
372\r
373\r
374static const char *start_capture (MatchState *ms, const char *s,\r
375 const char *p, int what) {\r
376 const char *res;\r
377 int level = ms->level;\r
378 if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures");\r
379 ms->capture[level].init = s;\r
380 ms->capture[level].len = what;\r
381 ms->level = level+1;\r
382 if ((res=match(ms, s, p)) == NULL) /* match failed? */\r
383 ms->level--; /* undo capture */\r
384 return res;\r
385}\r
386\r
387\r
388static const char *end_capture (MatchState *ms, const char *s,\r
389 const char *p) {\r
390 int l = capture_to_close(ms);\r
391 const char *res;\r
392 ms->capture[l].len = s - ms->capture[l].init; /* close capture */\r
393 if ((res = match(ms, s, p)) == NULL) /* match failed? */\r
394 ms->capture[l].len = CAP_UNFINISHED; /* undo capture */\r
395 return res;\r
396}\r
397\r
398\r
399static const char *match_capture (MatchState *ms, const char *s, int l) {\r
400 size_t len;\r
401 l = check_capture(ms, l);\r
402 len = ms->capture[l].len;\r
403 if ((size_t)(ms->src_end-s) >= len &&\r
404 memcmp(ms->capture[l].init, s, len) == 0)\r
405 return s+len;\r
406 else return NULL;\r
407}\r
408\r
409\r
410static const char *match (MatchState *ms, const char *s, const char *p) {\r
411 if (ms->matchdepth-- == 0)\r
412 luaL_error(ms->L, "pattern too complex");\r
413 init: /* using goto's to optimize tail recursion */\r
414 if (p != ms->p_end) { /* end of pattern? */\r
415 switch (*p) {\r
416 case '(': { /* start capture */\r
417 if (*(p + 1) == ')') /* position capture? */\r
418 s = start_capture(ms, s, p + 2, CAP_POSITION);\r
419 else\r
420 s = start_capture(ms, s, p + 1, CAP_UNFINISHED);\r
421 break;\r
422 }\r
423 case ')': { /* end capture */\r
424 s = end_capture(ms, s, p + 1);\r
425 break;\r
426 }\r
427 case '$': {\r
428 if ((p + 1) != ms->p_end) /* is the `$' the last char in pattern? */\r
429 goto dflt; /* no; go to default */\r
430 s = (s == ms->src_end) ? s : NULL; /* check end of string */\r
431 break;\r
432 }\r
433 case L_ESC: { /* escaped sequences not in the format class[*+?-]? */\r
434 switch (*(p + 1)) {\r
435 case 'b': { /* balanced string? */\r
436 s = matchbalance(ms, s, p + 2);\r
437 if (s != NULL) {\r
438 p += 4; goto init; /* return match(ms, s, p + 4); */\r
439 } /* else fail (s == NULL) */\r
440 break;\r
441 }\r
442 case 'f': { /* frontier? */\r
443 const char *ep; char previous;\r
444 p += 2;\r
445 if (*p != '[')\r
446 luaL_error(ms->L, "missing " LUA_QL("[") " after "\r
447 LUA_QL("%%f") " in pattern");\r
448 ep = classend(ms, p); /* points to what is next */\r
449 previous = (s == ms->src_init) ? '\0' : *(s - 1);\r
450 if (!matchbracketclass(uchar(previous), p, ep - 1) &&\r
451 matchbracketclass(uchar(*s), p, ep - 1)) {\r
452 p = ep; goto init; /* return match(ms, s, ep); */\r
453 }\r
454 s = NULL; /* match failed */\r
455 break;\r
456 }\r
457 case '0': case '1': case '2': case '3':\r
458 case '4': case '5': case '6': case '7':\r
459 case '8': case '9': { /* capture results (%0-%9)? */\r
460 s = match_capture(ms, s, uchar(*(p + 1)));\r
461 if (s != NULL) {\r
462 p += 2; goto init; /* return match(ms, s, p + 2) */\r
463 }\r
464 break;\r
465 }\r
466 default: goto dflt;\r
467 }\r
468 break;\r
469 }\r
470 default: dflt: { /* pattern class plus optional suffix */\r
471 const char *ep = classend(ms, p); /* points to optional suffix */\r
472 /* does not match at least once? */\r
473 if (!singlematch(ms, s, p, ep)) {\r
474 if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */\r
475 p = ep + 1; goto init; /* return match(ms, s, ep + 1); */\r
476 }\r
477 else /* '+' or no suffix */\r
478 s = NULL; /* fail */\r
479 }\r
480 else { /* matched once */\r
481 switch (*ep) { /* handle optional suffix */\r
482 case '?': { /* optional */\r
483 const char *res;\r
484 if ((res = match(ms, s + 1, ep + 1)) != NULL)\r
485 s = res;\r
486 else {\r
487 p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */\r
488 }\r
489 break;\r
490 }\r
491 case '+': /* 1 or more repetitions */\r
492 s++; /* 1 match already done */\r
493 /* go through */\r
494 case '*': /* 0 or more repetitions */\r
495 s = max_expand(ms, s, p, ep);\r
496 break;\r
497 case '-': /* 0 or more repetitions (minimum) */\r
498 s = min_expand(ms, s, p, ep);\r
499 break;\r
500 default: /* no suffix */\r
501 s++; p = ep; goto init; /* return match(ms, s + 1, ep); */\r
502 }\r
503 }\r
504 break;\r
505 }\r
506 }\r
507 }\r
508 ms->matchdepth++;\r
509 return s;\r
510}\r
511\r
512\r
513\r
514static const char *lmemfind (const char *s1, size_t l1,\r
515 const char *s2, size_t l2) {\r
516 if (l2 == 0) return s1; /* empty strings are everywhere */\r
517 else if (l2 > l1) return NULL; /* avoids a negative `l1' */\r
518 else {\r
519 const char *init; /* to search for a `*s2' inside `s1' */\r
520 l2--; /* 1st char will be checked by `memchr' */\r
521 l1 = l1-l2; /* `s2' cannot be found after that */\r
522 while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {\r
523 init++; /* 1st char is already checked */\r
524 if (memcmp(init, s2+1, l2) == 0)\r
525 return init-1;\r
526 else { /* correct `l1' and `s1' to try again */\r
527 l1 -= init-s1;\r
528 s1 = init;\r
529 }\r
530 }\r
531 return NULL; /* not found */\r
532 }\r
533}\r
534\r
535\r
536static void push_onecapture (MatchState *ms, int i, const char *s,\r
537 const char *e) {\r
538 if (i >= ms->level) {\r
539 if (i == 0) /* ms->level == 0, too */\r
540 lua_pushlstring(ms->L, s, e - s); /* add whole match */\r
541 else\r
542 luaL_error(ms->L, "invalid capture index");\r
543 }\r
544 else {\r
545 ptrdiff_t l = ms->capture[i].len;\r
546 if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");\r
547 if (l == CAP_POSITION)\r
548 lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);\r
549 else\r
550 lua_pushlstring(ms->L, ms->capture[i].init, l);\r
551 }\r
552}\r
553\r
554\r
555static int push_captures (MatchState *ms, const char *s, const char *e) {\r
556 int i;\r
557 int nlevels = (ms->level == 0 && s) ? 1 : ms->level;\r
558 luaL_checkstack(ms->L, nlevels, "too many captures");\r
559 for (i = 0; i < nlevels; i++)\r
560 push_onecapture(ms, i, s, e);\r
561 return nlevels; /* number of strings pushed */\r
562}\r
563\r
564\r
565/* check whether pattern has no special characters */\r
566static int nospecials (const char *p, size_t l) {\r
567 size_t upto = 0;\r
568 do {\r
569 if (strpbrk(p + upto, SPECIALS))\r
570 return 0; /* pattern has a special character */\r
571 upto += strlen(p + upto) + 1; /* may have more after \0 */\r
572 } while (upto <= l);\r
573 return 1; /* no special chars found */\r
574}\r
575\r
576\r
577static int str_find_aux (lua_State *L, int find) {\r
578 size_t ls, lp;\r
579 const char *s = luaL_checklstring(L, 1, &ls);\r
580 const char *p = luaL_checklstring(L, 2, &lp);\r
581 size_t init = posrelat(luaL_optinteger(L, 3, 1), ls);\r
582 if (init < 1) init = 1;\r
583 else if (init > ls + 1) { /* start after string's end? */\r
584 lua_pushnil(L); /* cannot find anything */\r
585 return 1;\r
586 }\r
587 /* explicit request or no special characters? */\r
588 if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) {\r
589 /* do a plain search */\r
590 const char *s2 = lmemfind(s + init - 1, ls - init + 1, p, lp);\r
591 if (s2) {\r
592 lua_pushinteger(L, s2 - s + 1);\r
593 lua_pushinteger(L, s2 - s + lp);\r
594 return 2;\r
595 }\r
596 }\r
597 else {\r
598 MatchState ms;\r
599 const char *s1 = s + init - 1;\r
600 int anchor = (*p == '^');\r
601 if (anchor) {\r
602 p++; lp--; /* skip anchor character */\r
603 }\r
604 ms.L = L;\r
605 ms.matchdepth = MAXCCALLS;\r
606 ms.src_init = s;\r
607 ms.src_end = s + ls;\r
608 ms.p_end = p + lp;\r
609 do {\r
610 const char *res;\r
611 ms.level = 0;\r
612 lua_assert(ms.matchdepth == MAXCCALLS);\r
613 if ((res=match(&ms, s1, p)) != NULL) {\r
614 if (find) {\r
615 lua_pushinteger(L, s1 - s + 1); /* start */\r
616 lua_pushinteger(L, res - s); /* end */\r
617 return push_captures(&ms, NULL, 0) + 2;\r
618 }\r
619 else\r
620 return push_captures(&ms, s1, res);\r
621 }\r
622 } while (s1++ < ms.src_end && !anchor);\r
623 }\r
624 lua_pushnil(L); /* not found */\r
625 return 1;\r
626}\r
627\r
628\r
629static int str_find (lua_State *L) {\r
630 return str_find_aux(L, 1);\r
631}\r
632\r
633\r
634static int str_match (lua_State *L) {\r
635 return str_find_aux(L, 0);\r
636}\r
637\r
638\r
639static int gmatch_aux (lua_State *L) {\r
640 MatchState ms;\r
641 size_t ls, lp;\r
642 const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);\r
643 const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp);\r
644 const char *src;\r
645 ms.L = L;\r
646 ms.matchdepth = MAXCCALLS;\r
647 ms.src_init = s;\r
648 ms.src_end = s+ls;\r
649 ms.p_end = p + lp;\r
650 for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3));\r
651 src <= ms.src_end;\r
652 src++) {\r
653 const char *e;\r
654 ms.level = 0;\r
655 lua_assert(ms.matchdepth == MAXCCALLS);\r
656 if ((e = match(&ms, src, p)) != NULL) {\r
657 lua_Integer newstart = e-s;\r
658 if (e == src) newstart++; /* empty match? go at least one position */\r
659 lua_pushinteger(L, newstart);\r
660 lua_replace(L, lua_upvalueindex(3));\r
661 return push_captures(&ms, src, e);\r
662 }\r
663 }\r
664 return 0; /* not found */\r
665}\r
666\r
667\r
668static int gmatch (lua_State *L) {\r
669 luaL_checkstring(L, 1);\r
670 luaL_checkstring(L, 2);\r
671 lua_settop(L, 2);\r
672 lua_pushinteger(L, 0);\r
673 lua_pushcclosure(L, gmatch_aux, 3);\r
674 return 1;\r
675}\r
676\r
677\r
678static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,\r
679 const char *e) {\r
680 size_t l, i;\r
681 const char *news = lua_tolstring(ms->L, 3, &l);\r
682 for (i = 0; i < l; i++) {\r
683 if (news[i] != L_ESC)\r
684 luaL_addchar(b, news[i]);\r
685 else {\r
686 i++; /* skip ESC */\r
687 if (!isdigit(uchar(news[i]))) {\r
688 if (news[i] != L_ESC)\r
689 luaL_error(ms->L, "invalid use of " LUA_QL("%c")\r
690 " in replacement string", L_ESC);\r
691 luaL_addchar(b, news[i]);\r
692 }\r
693 else if (news[i] == '0')\r
694 luaL_addlstring(b, s, e - s);\r
695 else {\r
696 push_onecapture(ms, news[i] - '1', s, e);\r
697 luaL_addvalue(b); /* add capture to accumulated result */\r
698 }\r
699 }\r
700 }\r
701}\r
702\r
703\r
704static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,\r
705 const char *e, int tr) {\r
706 lua_State *L = ms->L;\r
707 switch (tr) {\r
708 case LUA_TFUNCTION: {\r
709 int n;\r
710 lua_pushvalue(L, 3);\r
711 n = push_captures(ms, s, e);\r
712 lua_call(L, n, 1);\r
713 break;\r
714 }\r
715 case LUA_TTABLE: {\r
716 push_onecapture(ms, 0, s, e);\r
717 lua_gettable(L, 3);\r
718 break;\r
719 }\r
720 default: { /* LUA_TNUMBER or LUA_TSTRING */\r
721 add_s(ms, b, s, e);\r
722 return;\r
723 }\r
724 }\r
725 if (!lua_toboolean(L, -1)) { /* nil or false? */\r
726 lua_pop(L, 1);\r
727 lua_pushlstring(L, s, e - s); /* keep original text */\r
728 }\r
729 else if (!lua_isstring(L, -1))\r
730 luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1));\r
731 luaL_addvalue(b); /* add result to accumulator */\r
732}\r
733\r
734\r
735static int str_gsub (lua_State *L) {\r
736 size_t srcl, lp;\r
737 const char *src = luaL_checklstring(L, 1, &srcl);\r
738 const char *p = luaL_checklstring(L, 2, &lp);\r
739 int tr = lua_type(L, 3);\r
740 size_t max_s = luaL_optinteger(L, 4, srcl+1);\r
741 int anchor = (*p == '^');\r
742 size_t n = 0;\r
743 MatchState ms;\r
744 luaL_Buffer b;\r
745 luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||\r
746 tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,\r
747 "string/function/table expected");\r
748 luaL_buffinit(L, &b);\r
749 if (anchor) {\r
750 p++; lp--; /* skip anchor character */\r
751 }\r
752 ms.L = L;\r
753 ms.matchdepth = MAXCCALLS;\r
754 ms.src_init = src;\r
755 ms.src_end = src+srcl;\r
756 ms.p_end = p + lp;\r
757 while (n < max_s) {\r
758 const char *e;\r
759 ms.level = 0;\r
760 lua_assert(ms.matchdepth == MAXCCALLS);\r
761 e = match(&ms, src, p);\r
762 if (e) {\r
763 n++;\r
764 add_value(&ms, &b, src, e, tr);\r
765 }\r
766 if (e && e>src) /* non empty match? */\r
767 src = e; /* skip it */\r
768 else if (src < ms.src_end)\r
769 luaL_addchar(&b, *src++);\r
770 else break;\r
771 if (anchor) break;\r
772 }\r
773 luaL_addlstring(&b, src, ms.src_end-src);\r
774 luaL_pushresult(&b);\r
775 lua_pushinteger(L, n); /* number of substitutions */\r
776 return 2;\r
777}\r
778\r
779/* }====================================================== */\r
780\r
781\r
782\r
783/*\r
784** {======================================================\r
785** STRING FORMAT\r
786** =======================================================\r
787*/\r
788\r
789/*\r
790** LUA_INTFRMLEN is the length modifier for integer conversions in\r
791** 'string.format'; LUA_INTFRM_T is the integer type corresponding to\r
792** the previous length\r
793*/\r
794#if !defined(LUA_INTFRMLEN) /* { */\r
795#if defined(LUA_USE_LONGLONG)\r
796\r
797#define LUA_INTFRMLEN "ll"\r
798#define LUA_INTFRM_T long long\r
799\r
800#else\r
801\r
802#define LUA_INTFRMLEN "l"\r
803#define LUA_INTFRM_T long\r
804\r
805#endif\r
806#endif /* } */\r
807\r
808\r
809/*\r
810** LUA_FLTFRMLEN is the length modifier for float conversions in\r
811** 'string.format'; LUA_FLTFRM_T is the float type corresponding to\r
812** the previous length\r
813*/\r
814#if !defined(LUA_FLTFRMLEN)\r
815\r
816#define LUA_FLTFRMLEN ""\r
817#define LUA_FLTFRM_T double\r
818\r
819#endif\r
820\r
821\r
822/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */\r
823#define MAX_ITEM 512\r
824/* valid flags in a format specification */\r
825#define FLAGS "-+ #0"\r
826/*\r
827** maximum size of each format specification (such as '%-099.99d')\r
828** (+10 accounts for %99.99x plus margin of error)\r
829*/\r
830#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10)\r
831\r
832\r
833static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {\r
834 size_t l;\r
835 const char *s = luaL_checklstring(L, arg, &l);\r
836 luaL_addchar(b, '"');\r
837 while (l--) {\r
838 if (*s == '"' || *s == '\\' || *s == '\n') {\r
839 luaL_addchar(b, '\\');\r
840 luaL_addchar(b, *s);\r
841 }\r
842 else if (*s == '\0' || iscntrl(uchar(*s))) {\r
843 char buff[10];\r
844 if (!isdigit(uchar(*(s+1))))\r
845 sprintf(buff, "\\%d", (int)uchar(*s));\r
846 else\r
847 sprintf(buff, "\\%03d", (int)uchar(*s));\r
848 luaL_addstring(b, buff);\r
849 }\r
850 else\r
851 luaL_addchar(b, *s);\r
852 s++;\r
853 }\r
854 luaL_addchar(b, '"');\r
855}\r
856\r
857static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {\r
858 const char *p = strfrmt;\r
859 while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */\r
860 if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char))\r
861 luaL_error(L, "invalid format (repeated flags)");\r
862 if (isdigit(uchar(*p))) p++; /* skip width */\r
863 if (isdigit(uchar(*p))) p++; /* (2 digits at most) */\r
864 if (*p == '.') {\r
865 p++;\r
866 if (isdigit(uchar(*p))) p++; /* skip precision */\r
867 if (isdigit(uchar(*p))) p++; /* (2 digits at most) */\r
868 }\r
869 if (isdigit(uchar(*p)))\r
870 luaL_error(L, "invalid format (width or precision too long)");\r
871 *(form++) = '%';\r
872 memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char));\r
873 form += p - strfrmt + 1;\r
874 *form = '\0';\r
875 return p;\r
876}\r
877\r
878\r
879/*\r
880** add length modifier into formats\r
881*/\r
882static void addlenmod (char *form, const char *lenmod) {\r
883 size_t l = strlen(form);\r
884 size_t lm = strlen(lenmod);\r
885 char spec = form[l - 1];\r
886 strcpy(form + l - 1, lenmod);\r
887 form[l + lm - 1] = spec;\r
888 form[l + lm] = '\0';\r
889}\r
890\r
891\r
892static int str_format (lua_State *L) {\r
893 int top = lua_gettop(L);\r
894 int arg = 1;\r
895 size_t sfl;\r
896 const char *strfrmt = luaL_checklstring(L, arg, &sfl);\r
897 const char *strfrmt_end = strfrmt+sfl;\r
898 luaL_Buffer b;\r
899 luaL_buffinit(L, &b);\r
900 while (strfrmt < strfrmt_end) {\r
901 if (*strfrmt != L_ESC)\r
902 luaL_addchar(&b, *strfrmt++);\r
903 else if (*++strfrmt == L_ESC)\r
904 luaL_addchar(&b, *strfrmt++); /* %% */\r
905 else { /* format item */\r
906 char form[MAX_FORMAT]; /* to store the format (`%...') */\r
907 char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */\r
908 int nb = 0; /* number of bytes in added item */\r
909 if (++arg > top)\r
910 luaL_argerror(L, arg, "no value");\r
911 strfrmt = scanformat(L, strfrmt, form);\r
912 switch (*strfrmt++) {\r
913 case 'c': {\r
914 nb = sprintf(buff, form, luaL_checkint(L, arg));\r
915 break;\r
916 }\r
917 case 'd': case 'i': {\r
918 lua_Number n = luaL_checknumber(L, arg);\r
919 LUA_INTFRM_T ni = (LUA_INTFRM_T)n;\r
920 lua_Number diff = n - (lua_Number)ni;\r
921 luaL_argcheck(L, -1 < diff && diff < 1, arg,\r
922 "not a number in proper range");\r
923 addlenmod(form, LUA_INTFRMLEN);\r
924 nb = sprintf(buff, form, ni);\r
925 break;\r
926 }\r
927 case 'o': case 'u': case 'x': case 'X': {\r
928 lua_Number n = luaL_checknumber(L, arg);\r
929 unsigned LUA_INTFRM_T ni = (unsigned LUA_INTFRM_T)n;\r
930 lua_Number diff = n - (lua_Number)ni;\r
931 luaL_argcheck(L, -1 < diff && diff < 1, arg,\r
932 "not a non-negative number in proper range");\r
933 addlenmod(form, LUA_INTFRMLEN);\r
934 nb = sprintf(buff, form, ni);\r
935 break;\r
936 }\r
937 case 'e': case 'E': case 'f':\r
938#if defined(LUA_USE_AFORMAT)\r
939 case 'a': case 'A':\r
940#endif\r
941 case 'g': case 'G': {\r
942 addlenmod(form, LUA_FLTFRMLEN);\r
943 nb = sprintf(buff, form, (LUA_FLTFRM_T)luaL_checknumber(L, arg));\r
944 break;\r
945 }\r
946 case 'q': {\r
947 addquoted(L, &b, arg);\r
948 break;\r
949 }\r
950 case 's': {\r
951 size_t l;\r
952 const char *s = luaL_tolstring(L, arg, &l);\r
953 if (!strchr(form, '.') && l >= 100) {\r
954 /* no precision and string is too long to be formatted;\r
955 keep original string */\r
956 luaL_addvalue(&b);\r
957 break;\r
958 }\r
959 else {\r
960 nb = sprintf(buff, form, s);\r
961 lua_pop(L, 1); /* remove result from 'luaL_tolstring' */\r
962 break;\r
963 }\r
964 }\r
965 default: { /* also treat cases `pnLlh' */\r
966 return luaL_error(L, "invalid option " LUA_QL("%%%c") " to "\r
967 LUA_QL("format"), *(strfrmt - 1));\r
968 }\r
969 }\r
970 luaL_addsize(&b, nb);\r
971 }\r
972 }\r
973 luaL_pushresult(&b);\r
974 return 1;\r
975}\r
976\r
977/* }====================================================== */\r
978\r
979\r
980static const luaL_Reg strlib[] = {\r
981 {"byte", str_byte},\r
982 {"char", str_char},\r
983 {"dump", str_dump},\r
984 {"find", str_find},\r
985 {"format", str_format},\r
986 {"gmatch", gmatch},\r
987 {"gsub", str_gsub},\r
988 {"len", str_len},\r
989 {"lower", str_lower},\r
990 {"match", str_match},\r
991 {"rep", str_rep},\r
992 {"reverse", str_reverse},\r
993 {"sub", str_sub},\r
994 {"upper", str_upper},\r
995 {NULL, NULL}\r
996};\r
997\r
998\r
999static void createmetatable (lua_State *L) {\r
1000 lua_createtable(L, 0, 1); /* table to be metatable for strings */\r
1001 lua_pushliteral(L, ""); /* dummy string */\r
1002 lua_pushvalue(L, -2); /* copy table */\r
1003 lua_setmetatable(L, -2); /* set table as metatable for strings */\r
1004 lua_pop(L, 1); /* pop dummy string */\r
1005 lua_pushvalue(L, -2); /* get string library */\r
1006 lua_setfield(L, -2, "__index"); /* metatable.__index = string */\r
1007 lua_pop(L, 1); /* pop metatable */\r
1008}\r
1009\r
1010\r
1011/*\r
1012** Open string library\r
1013*/\r
1014LUAMOD_API int luaopen_string (lua_State *L) {\r
1015 luaL_newlib(L, strlib);\r
1016 createmetatable(L);\r
1017 return 1;\r
1018}\r
1019\r