LCOV - code coverage report
Current view: top level - src - luasandbox_lstrlib.c (source / functions) Hit Total Coverage
Test: mediawiki/php/luasandbox test coverage report Lines: 40 512 7.8 %
Date: 2023-12-12 07:35:14 Functions: 5 43 11.6 %

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

Generated by: LCOV version 1.13