LCOV - code coverage report
Current view: top level - AP_Scripting/lua/src - lstrlib.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 614 803 76.5 %
Date: 2026-09-09 11:02:08 Functions: 51 58 87.9 %

          Line data    Source code
       1             : /*
       2             : ** $Id: lstrlib.c,v 1.254.1.1 2017/04/19 17:29:57 roberto Exp $
       3             : ** Standard library for string operations and pattern-matching
       4             : ** See Copyright Notice in lua.h
       5             : */
       6             : 
       7             : #define lstrlib_c
       8             : #define LUA_LIB
       9             : 
      10             : #include "lprefix.h"
      11             : 
      12             : 
      13             : #include <ctype.h>
      14             : #include <float.h>
      15             : #include <limits.h>
      16             : #include <locale.h>
      17             : #include <stddef.h>
      18             : #include <stdio.h>
      19             : #include <stdlib.h>
      20             : #include <string.h>
      21             : 
      22             : #include "lua.h"
      23             : 
      24             : #include "lauxlib.h"
      25             : #include "lualib.h"
      26             : 
      27             : #if defined(ARDUPILOT_BUILD)
      28             : #pragma GCC diagnostic ignored "-Wunused-function"
      29             : #if defined(__GNUC__) &&  __GNUC__ >= 7 || defined(__clang_major__) && __clang_major__ >= 10
      30             : #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
      31             : #endif
      32             : #endif
      33             : 
      34             : 
      35             : /*
      36             : ** maximum number of captures that a pattern can do during
      37             : ** pattern-matching. This limit is arbitrary, but must fit in
      38             : ** an unsigned char.
      39             : */
      40             : #if !defined(LUA_MAXCAPTURES)
      41             : #define LUA_MAXCAPTURES         32
      42             : #endif
      43             : 
      44             : 
      45             : /* macro to 'unsign' a character */
      46             : #define uchar(c)        ((unsigned char)(c))
      47             : 
      48             : 
      49             : /*
      50             : ** Some sizes are better limited to fit in 'int', but must also fit in
      51             : ** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.)
      52             : */
      53             : #define MAX_SIZET       ((size_t)(~(size_t)0))
      54             : 
      55             : #define MAXSIZE  \
      56             :         (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX))
      57             : 
      58             : 
      59             : 
      60             : 
      61          70 : static int str_len (lua_State *L) {
      62             :   size_t l;
      63          70 :   luaL_checklstring(L, 1, &l);
      64          70 :   lua_pushinteger(L, (lua_Integer)l);
      65          70 :   return 1;
      66             : }
      67             : 
      68             : 
      69             : /* translate a relative string position: negative means back from end */
      70       16596 : static lua_Integer posrelat (lua_Integer pos, size_t len) {
      71       16596 :   if (pos >= 0) return pos;
      72        7201 :   else if (0u - (size_t)pos > len) return 0;
      73        7182 :   else return (lua_Integer)len + pos + 1;
      74             : }
      75             : 
      76             : 
      77        8065 : static int str_sub (lua_State *L) {
      78             :   size_t l;
      79        8065 :   const char *s = luaL_checklstring(L, 1, &l);
      80        8065 :   lua_Integer start = posrelat(luaL_checkinteger(L, 2), l);
      81        8065 :   lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l);
      82        8065 :   if (start < 1) start = 1;
      83        8065 :   if (end > (lua_Integer)l) end = l;
      84        8065 :   if (start <= end)
      85        8057 :     lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1);
      86           8 :   else lua_pushliteral(L, "");
      87        8065 :   return 1;
      88             : }
      89             : 
      90             : 
      91           6 : static int str_reverse (lua_State *L) {
      92             :   size_t l, i;
      93             :   luaL_Buffer b;
      94           6 :   const char *s = luaL_checklstring(L, 1, &l);
      95           6 :   char *p = luaL_buffinitsize(L, &b, l);
      96          24 :   for (i = 0; i < l; i++)
      97          18 :     p[i] = s[l - i - 1];
      98           6 :   luaL_pushresultsize(&b, l);
      99           6 :   return 1;
     100             : }
     101             : 
     102             : 
     103           3 : static int str_lower (lua_State *L) {
     104             :   size_t l;
     105             :   size_t i;
     106             :   luaL_Buffer b;
     107           3 :   const char *s = luaL_checklstring(L, 1, &l);
     108           3 :   char *p = luaL_buffinitsize(L, &b, l);
     109          22 :   for (i=0; i<l; i++)
     110          19 :     p[i] = tolower(uchar(s[i]));
     111           3 :   luaL_pushresultsize(&b, l);
     112           3 :   return 1;
     113             : }
     114             : 
     115             : 
     116           2 : static int str_upper (lua_State *L) {
     117             :   size_t l;
     118             :   size_t i;
     119             :   luaL_Buffer b;
     120           2 :   const char *s = luaL_checklstring(L, 1, &l);
     121           2 :   char *p = luaL_buffinitsize(L, &b, l);
     122          10 :   for (i=0; i<l; i++)
     123           8 :     p[i] = toupper(uchar(s[i]));
     124           2 :   luaL_pushresultsize(&b, l);
     125           2 :   return 1;
     126             : }
     127             : 
     128             : 
     129         129 : static int str_rep (lua_State *L) {
     130             :   size_t l, lsep;
     131         129 :   const char *s = luaL_checklstring(L, 1, &l);
     132         129 :   lua_Integer n = luaL_checkinteger(L, 2);
     133         129 :   const char *sep = luaL_optlstring(L, 3, "", &lsep);
     134         129 :   if (n <= 0) lua_pushliteral(L, "");
     135         123 :   else if (l + lsep < l || l + lsep > MAXSIZE / n)  /* may overflow? */
     136           8 :     return luaL_error(L, "resulting string too large");
     137             :   else {
     138         115 :     size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep;
     139             :     luaL_Buffer b;
     140         115 :     char *p = luaL_buffinitsize(L, &b, totallen);
     141       24012 :     while (n-- > 1) {  /* first n-1 copies (followed by separator) */
     142       23897 :       memcpy(p, s, l * sizeof(char)); p += l;
     143       23897 :       if (lsep > 0) {  /* empty 'memcpy' is not that cheap */
     144          20 :         memcpy(p, sep, lsep * sizeof(char));
     145          20 :         p += lsep;
     146             :       }
     147             :     }
     148         115 :     memcpy(p, s, l * sizeof(char));  /* last copy (not followed by separator) */
     149         115 :     luaL_pushresultsize(&b, totallen);
     150             :   }
     151         121 :   return 1;
     152             : }
     153             : 
     154             : 
     155          96 : static int str_byte (lua_State *L) {
     156             :   size_t l;
     157          96 :   const char *s = luaL_checklstring(L, 1, &l);
     158          96 :   lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l);
     159          96 :   lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l);
     160             :   int n, i;
     161          96 :   if (posi < 1) posi = 1;
     162          96 :   if (pose > (lua_Integer)l) pose = l;
     163          96 :   if (posi > pose) return 0;  /* empty interval; return no values */
     164          84 :   if (pose - posi >= INT_MAX)  /* arithmetic overflow? */
     165           0 :     return luaL_error(L, "string slice too long");
     166          84 :   n = (int)(pose -  posi) + 1;
     167          84 :   luaL_checkstack(L, n, "string slice too long");
     168         192 :   for (i=0; i<n; i++)
     169         108 :     lua_pushinteger(L, uchar(s[posi+i-1]));
     170          84 :   return n;
     171             : }
     172             : 
     173             : 
     174          30 : static int str_char (lua_State *L) {
     175          30 :   int n = lua_gettop(L);  /* number of arguments */
     176             :   int i;
     177             :   luaL_Buffer b;
     178          30 :   char *p = luaL_buffinitsize(L, &b, n);
     179          88 :   for (i=1; i<=n; i++) {
     180          58 :     lua_Integer c = luaL_checkinteger(L, i);
     181          58 :     luaL_argcheck(L, uchar(c) == c, i, "value out of range");
     182          58 :     p[i - 1] = uchar(c);
     183             :   }
     184          30 :   luaL_pushresultsize(&b, n);
     185          30 :   return 1;
     186             : }
     187             : 
     188             : 
     189           0 : static int writer (lua_State *L, const void *b, size_t size, void *B) {
     190             :   (void)L;
     191           0 :   luaL_addlstring((luaL_Buffer *) B, (const char *)b, size);
     192           0 :   return 0;
     193             : }
     194             : 
     195             : 
     196           0 : static int str_dump (lua_State *L) {
     197             :   luaL_Buffer b;
     198           0 :   int strip = lua_toboolean(L, 2);
     199           0 :   luaL_checktype(L, 1, LUA_TFUNCTION);
     200           0 :   lua_settop(L, 1);
     201           0 :   luaL_buffinit(L,&b);
     202           0 :   if (lua_dump(L, writer, &b, strip) != 0)
     203           0 :     return luaL_error(L, "unable to dump given function");
     204           0 :   luaL_pushresult(&b);
     205           0 :   return 1;
     206             : }
     207             : 
     208             : 
     209             : 
     210             : /*
     211             : ** {======================================================
     212             : ** PATTERN MATCHING
     213             : ** =======================================================
     214             : */
     215             : 
     216             : 
     217             : #define CAP_UNFINISHED  (-1)
     218             : #define CAP_POSITION    (-2)
     219             : 
     220             : 
     221             : typedef struct MatchState {
     222             :   const char *src_init;  /* init of source string */
     223             :   const char *src_end;  /* end ('\0') of source string */
     224             :   const char *p_end;  /* end ('\0') of pattern */
     225             :   lua_State *L;
     226             :   int matchdepth;  /* control for recursive depth (to avoid C stack overflow) */
     227             :   unsigned char level;  /* total number of captures (finished or unfinished) */
     228             :   struct {
     229             :     const char *init;
     230             :     ptrdiff_t len;
     231             :   } capture[LUA_MAXCAPTURES];
     232             : } MatchState;
     233             : 
     234             : 
     235             : /* recursive function */
     236             : static const char *match (MatchState *ms, const char *s, const char *p);
     237             : 
     238             : 
     239             : /* maximum recursion depth for 'match' */
     240             : #if !defined(MAXCCALLS)
     241             : #define MAXCCALLS       200
     242             : #endif
     243             : 
     244             : 
     245             : #define L_ESC           '%'
     246             : #define SPECIALS        "^$*+?.([%-"
     247             : 
     248             : 
     249           0 : static int check_capture (MatchState *ms, int l) {
     250           0 :   l -= '1';
     251           0 :   if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
     252           0 :     return luaL_error(ms->L, "invalid capture index %%%d", l + 1);
     253           0 :   return l;
     254             : }
     255             : 
     256             : 
     257      604020 : static int capture_to_close (MatchState *ms) {
     258      604020 :   int level = ms->level;
     259      604030 :   for (level--; level>=0; level--)
     260      604030 :     if (ms->capture[level].len == CAP_UNFINISHED) return level;
     261           0 :   return luaL_error(ms->L, "invalid pattern capture");
     262             : }
     263             : 
     264             : 
     265      667950 : static const char *classend (MatchState *ms, const char *p) {
     266      667950 :   switch (*p++) {
     267        1783 :     case L_ESC: {
     268        1783 :       if (p == ms->p_end)
     269           0 :         luaL_error(ms->L, "malformed pattern (ends with '%%')");
     270        1783 :       return p+1;
     271             :     }
     272      642531 :     case '[': {
     273      642531 :       if (*p == '^') p++;
     274             :       do {  /* look for a ']' */
     275      643639 :         if (p == ms->p_end)
     276           0 :           luaL_error(ms->L, "malformed pattern (missing ']')");
     277      643639 :         if (*(p++) == L_ESC && p < ms->p_end)
     278         254 :           p++;  /* skip escapes (e.g. '%]') */
     279      643639 :       } while (*p != ']');
     280      642531 :       return p+1;
     281             :     }
     282       23636 :     default: {
     283       23636 :       return p;
     284             :     }
     285             :   }
     286             : }
     287             : 
     288             : 
     289        3024 : static int match_class (int c, int cl) {
     290             :   int res;
     291        3024 :   switch (tolower(cl)) {
     292           0 :     case 'a' : res = isalpha(c); break;
     293           0 :     case 'c' : res = iscntrl(c); break;
     294         259 :     case 'd' : res = isdigit(c); break;
     295           0 :     case 'g' : res = isgraph(c); break;
     296           0 :     case 'l' : res = islower(c); break;
     297           0 :     case 'p' : res = ispunct(c); break;
     298        1913 :     case 's' : res = isspace(c); break;
     299           0 :     case 'u' : res = isupper(c); break;
     300         712 :     case 'w' : res = isalnum(c); break;
     301           8 :     case 'x' : res = isxdigit(c); break;
     302           0 :     case 'z' : res = (c == 0); break;  /* deprecated option */
     303         132 :     default: return (cl == c);
     304             :   }
     305        2892 :   return (islower(cl) ? res : !res);
     306             : }
     307             : 
     308             : 
     309      640519 : static int matchbracketclass (int c, const char *p, const char *ec) {
     310      640519 :   int sig = 1;
     311      640519 :   if (*(p+1) == '^') {
     312         313 :     sig = 0;
     313         313 :     p++;  /* skip the '^' */
     314             :   }
     315     1236993 :   while (++p < ec) {
     316      641334 :     if (*p == L_ESC) {
     317         858 :       p++;
     318         858 :       if (match_class(c, uchar(*p)))
     319         687 :         return sig;
     320             :     }
     321      640476 :     else if ((*(p+1) == '-') && (p+2 < ec)) {
     322         448 :       p+=2;
     323         448 :       if (uchar(*(p-2)) <= c && c <= uchar(*p))
     324         304 :         return sig;
     325             :     }
     326      640028 :     else if (uchar(*p) == c) return sig;
     327             :   }
     328      595659 :   return !sig;
     329             : }
     330             : 
     331             : 
     332     1275952 : static int singlematch (MatchState *ms, const char *s, const char *p,
     333             :                         const char *ep) {
     334     1275952 :   if (s >= ms->src_end)
     335        8519 :     return 0;
     336             :   else {
     337     1267433 :     int c = uchar(*s);
     338     1267433 :     switch (*p) {
     339      606245 :       case '.': return 1;  /* matches any char */
     340        2166 :       case L_ESC: return match_class(c, uchar(*(p+1)));
     341      640519 :       case '[': return matchbracketclass(c, p, ep-1);
     342       18503 :       default:  return (uchar(*p) == c);
     343             :     }
     344             :   }
     345             : }
     346             : 
     347             : 
     348           0 : static const char *matchbalance (MatchState *ms, const char *s,
     349             :                                    const char *p) {
     350           0 :   if (p >= ms->p_end - 1)
     351           0 :     luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')");
     352           0 :   if (*s != *p) return NULL;
     353             :   else {
     354           0 :     int b = *p;
     355           0 :     int e = *(p+1);
     356           0 :     int cont = 1;
     357           0 :     while (++s < ms->src_end) {
     358           0 :       if (*s == e) {
     359           0 :         if (--cont == 0) return s+1;
     360             :       }
     361           0 :       else if (*s == b) cont++;
     362             :     }
     363             :   }
     364           0 :   return NULL;  /* string ends out of balance */
     365             : }
     366             : 
     367             : 
     368         471 : static const char *max_expand (MatchState *ms, const char *s,
     369             :                                  const char *p, const char *ep) {
     370         471 :   ptrdiff_t i = 0;  /* counts maximum expand for item */
     371        4442 :   while (singlematch(ms, s + i, p, ep))
     372        3971 :     i++;
     373             :   /* keeps trying to match with the maximum repetitions */
     374        1174 :   while (i>=0) {
     375        1013 :     const char *res = match(ms, (s+i), ep+1);
     376        1013 :     if (res) return res;
     377         703 :     i--;  /* else didn't match; reduce 1 repetition to try again */
     378             :   }
     379         161 :   return NULL;
     380             : }
     381             : 
     382             : 
     383      603622 : static const char *min_expand (MatchState *ms, const char *s,
     384             :                                  const char *p, const char *ep) {
     385      600424 :   for (;;) {
     386      603622 :     const char *res = match(ms, s, ep+1);
     387      603622 :     if (res != NULL)
     388          62 :       return res;
     389      603560 :     else if (singlematch(ms, s, p, ep))
     390      600424 :       s++;  /* try with one more repetition */
     391        3136 :     else return NULL;
     392             :   }
     393             : }
     394             : 
     395             : 
     396        3681 : static const char *start_capture (MatchState *ms, const char *s,
     397             :                                     const char *p, int what) {
     398             :   const char *res;
     399        3681 :   int level = ms->level;
     400        3681 :   if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures");
     401        3681 :   ms->capture[level].init = s;
     402        3681 :   ms->capture[level].len = what;
     403        3681 :   ms->level = level+1;
     404        3681 :   if ((res=match(ms, s, p)) == NULL)  /* match failed? */
     405        3338 :     ms->level--;  /* undo capture */
     406        3681 :   return res;
     407             : }
     408             : 
     409             : 
     410      604020 : static const char *end_capture (MatchState *ms, const char *s,
     411             :                                   const char *p) {
     412      604020 :   int l = capture_to_close(ms);
     413             :   const char *res;
     414      604020 :   ms->capture[l].len = s - ms->capture[l].init;  /* close capture */
     415      604020 :   if ((res = match(ms, s, p)) == NULL)  /* match failed? */
     416      603677 :     ms->capture[l].len = CAP_UNFINISHED;  /* undo capture */
     417      604020 :   return res;
     418             : }
     419             : 
     420             : 
     421           0 : static const char *match_capture (MatchState *ms, const char *s, int l) {
     422             :   size_t len;
     423           0 :   l = check_capture(ms, l);
     424           0 :   len = ms->capture[l].len;
     425           0 :   if ((size_t)(ms->src_end-s) >= len &&
     426           0 :       memcmp(ms->capture[l].init, s, len) == 0)
     427           0 :     return s+len;
     428           0 :   else return NULL;
     429             : }
     430             : 
     431             : 
     432     1225620 : static const char *match (MatchState *ms, const char *s, const char *p) {
     433     1225620 :   if (ms->matchdepth-- == 0)
     434           0 :     luaL_error(ms->L, "pattern too complex");
     435     1225620 :   init: /* using goto's to optimize tail recursion */
     436     1279258 :   if (p != ms->p_end) {  /* end of pattern? */
     437     1277296 :     switch (*p) {
     438        3681 :       case '(': {  /* start capture */
     439        3681 :         if (*(p + 1) == ')')  /* position capture? */
     440           0 :           s = start_capture(ms, s, p + 2, CAP_POSITION);
     441             :         else
     442        3681 :           s = start_capture(ms, s, p + 1, CAP_UNFINISHED);
     443        3681 :         break;
     444             :       }
     445      604020 :       case ')': {  /* end capture */
     446      604020 :         s = end_capture(ms, s, p + 1);
     447      604020 :         break;
     448             :       }
     449        1645 :       case '$': {
     450        1645 :         if ((p + 1) != ms->p_end)  /* is the '$' the last char in pattern? */
     451           0 :           goto dflt;  /* no; go to default */
     452        1645 :         s = (s == ms->src_end) ? s : NULL;  /* check end of string */
     453        1645 :         break;
     454             :       }
     455        1783 :       case L_ESC: {  /* escaped sequences not in the format class[*+?-]? */
     456        1783 :         switch (*(p + 1)) {
     457           0 :           case 'b': {  /* balanced string? */
     458           0 :             s = matchbalance(ms, s, p + 2);
     459           0 :             if (s != NULL) {
     460           0 :               p += 4; goto init;  /* return match(ms, s, p + 4); */
     461             :             }  /* else fail (s == NULL) */
     462           0 :             break;
     463             :           }
     464           0 :           case 'f': {  /* frontier? */
     465             :             const char *ep; char previous;
     466           0 :             p += 2;
     467           0 :             if (*p != '[')
     468           0 :               luaL_error(ms->L, "missing '[' after '%%f' in pattern");
     469           0 :             ep = classend(ms, p);  /* points to what is next */
     470           0 :             previous = (s == ms->src_init) ? '\0' : *(s - 1);
     471           0 :             if (!matchbracketclass(uchar(previous), p, ep - 1) &&
     472           0 :                matchbracketclass(uchar(*s), p, ep - 1)) {
     473           0 :               p = ep; goto init;  /* return match(ms, s, ep); */
     474             :             }
     475           0 :             s = NULL;  /* match failed */
     476           0 :             break;
     477             :           }
     478           0 :           case '0': case '1': case '2': case '3':
     479             :           case '4': case '5': case '6': case '7':
     480             :           case '8': case '9': {  /* capture results (%0-%9)? */
     481           0 :             s = match_capture(ms, s, uchar(*(p + 1)));
     482           0 :             if (s != NULL) {
     483           0 :               p += 2; goto init;  /* return match(ms, s, p + 2) */
     484             :             }
     485           0 :             break;
     486             :           }
     487        1783 :           default: goto dflt;
     488             :         }
     489           0 :         break;
     490             :       }
     491      667950 :       default: dflt: {  /* pattern class plus optional suffix */
     492      667950 :         const char *ep = classend(ms, p);  /* points to optional suffix */
     493             :         /* does not match at least once? */
     494      667950 :         if (!singlematch(ms, s, p, ep)) {
     495      612039 :           if (*ep == '*' || *ep == '?' || *ep == '-') {  /* accept empty? */
     496        1522 :             p = ep + 1; goto init;  /* return match(ms, s, ep + 1); */
     497             :           }
     498             :           else  /* '+' or no suffix */
     499      610517 :             s = NULL;  /* fail */
     500             :         }
     501             :         else {  /* matched once */
     502       55911 :           switch (*ep) {  /* handle optional suffix */
     503         126 :             case '?': {  /* optional */
     504             :               const char *res;
     505         126 :               if ((res = match(ms, s + 1, ep + 1)) != NULL)
     506         126 :                 s = res;
     507             :               else {
     508           0 :                 p = ep + 1; goto init;  /* else return match(ms, s, ep + 1); */
     509             :               }
     510         126 :               break;
     511             :             }
     512         143 :             case '+':  /* 1 or more repetitions */
     513         143 :               s++;  /* 1 match already done */
     514             :               /* FALLTHROUGH */
     515         471 :             case '*':  /* 0 or more repetitions */
     516         471 :               s = max_expand(ms, s, p, ep);
     517         471 :               break;
     518        3198 :             case '-':  /* 0 or more repetitions (minimum) */
     519        3198 :               s = min_expand(ms, s, p, ep);
     520        3198 :               break;
     521       52116 :             default:  /* no suffix */
     522       52116 :               s++; p = ep; goto init;  /* return match(ms, s + 1, ep); */
     523             :           }
     524             :         }
     525      614312 :         break;
     526             :       }
     527             :     }
     528             :   }
     529     1225620 :   ms->matchdepth++;
     530     1225620 :   return s;
     531             : }
     532             : 
     533             : 
     534             : 
     535          51 : static const char *lmemfind (const char *s1, size_t l1,
     536             :                                const char *s2, size_t l2) {
     537          51 :   if (l2 == 0) return s1;  /* empty strings are everywhere */
     538          47 :   else if (l2 > l1) return NULL;  /* avoids a negative 'l1' */
     539             :   else {
     540             :     const char *init;  /* to search for a '*s2' inside 's1' */
     541          45 :     l2--;  /* 1st char will be checked by 'memchr' */
     542          45 :     l1 = l1-l2;  /* 's2' cannot be found after that */
     543          89 :     while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
     544          85 :       init++;   /* 1st char is already checked */
     545          85 :       if (memcmp(init, s2+1, l2) == 0)
     546          41 :         return init-1;
     547             :       else {  /* correct 'l1' and 's1' to try again */
     548          44 :         l1 -= init-s1;
     549          44 :         s1 = init;
     550             :       }
     551             :     }
     552           4 :     return NULL;  /* not found */
     553             :   }
     554             : }
     555             : 
     556             : 
     557         363 : static void push_onecapture (MatchState *ms, int i, const char *s,
     558             :                                                     const char *e) {
     559         363 :   if (i >= ms->level) {
     560          20 :     if (i == 0)  /* ms->level == 0, too */
     561          20 :       lua_pushlstring(ms->L, s, e - s);  /* add whole match */
     562             :     else
     563           0 :       luaL_error(ms->L, "invalid capture index %%%d", i + 1);
     564             :   }
     565             :   else {
     566         343 :     ptrdiff_t l = ms->capture[i].len;
     567         343 :     if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
     568         343 :     if (l == CAP_POSITION)
     569           0 :       lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1);
     570             :     else
     571         343 :       lua_pushlstring(ms->L, ms->capture[i].init, l);
     572             :   }
     573         363 : }
     574             : 
     575             : 
     576         181 : static int push_captures (MatchState *ms, const char *s, const char *e) {
     577             :   int i;
     578         181 :   int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
     579         181 :   luaL_checkstack(ms->L, nlevels, "too many captures");
     580         481 :   for (i = 0; i < nlevels; i++)
     581         300 :     push_onecapture(ms, i, s, e);
     582         181 :   return nlevels;  /* number of strings pushed */
     583             : }
     584             : 
     585             : 
     586             : /* check whether pattern has no special characters */
     587         203 : static int nospecials (const char *p, size_t l) {
     588         203 :   size_t upto = 0;
     589             :   do {
     590         203 :     if (strpbrk(p + upto, SPECIALS))
     591         156 :       return 0;  /* pattern has a special character */
     592          47 :     upto += strlen(p + upto) + 1;  /* may have more after \0 */
     593          47 :   } while (upto <= l);
     594          47 :   return 1;  /* no special chars found */
     595             : }
     596             : 
     597             : 
     598        2102 : static void prepstate (MatchState *ms, lua_State *L,
     599             :                        const char *s, size_t ls, const char *p, size_t lp) {
     600        2102 :   ms->L = L;
     601        2102 :   ms->matchdepth = MAXCCALLS;
     602        2102 :   ms->src_init = s;
     603        2102 :   ms->src_end = s + ls;
     604        2102 :   ms->p_end = p + lp;
     605        2102 : }
     606             : 
     607             : 
     608       13158 : static void reprepstate (MatchState *ms) {
     609       13158 :   ms->level = 0;
     610             :   lua_assert(ms->matchdepth == MAXCCALLS);
     611       13158 : }
     612             : 
     613             : 
     614         240 : static int str_find_aux (lua_State *L, int find) {
     615             :   size_t ls, lp;
     616         240 :   const char *s = luaL_checklstring(L, 1, &ls);
     617         240 :   const char *p = luaL_checklstring(L, 2, &lp);
     618         240 :   lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls);
     619         240 :   if (init < 1) init = 1;
     620         240 :   else if (init > (lua_Integer)ls + 1) {  /* start after string's end? */
     621           2 :     lua_pushnil(L);  /* cannot find anything */
     622           2 :     return 1;
     623             :   }
     624             :   /* explicit request or no special characters? */
     625         244 :   if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) {
     626             :     /* do a plain search */
     627          51 :     const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp);
     628          51 :     if (s2) {
     629          45 :       lua_pushinteger(L, (s2 - s) + 1);
     630          45 :       lua_pushinteger(L, (s2 - s) + lp);
     631          45 :       return 2;
     632             :     }
     633             :   }
     634             :   else {
     635             :     MatchState ms;
     636         187 :     const char *s1 = s + init - 1;
     637         187 :     int anchor = (*p == '^');
     638         187 :     if (anchor) {
     639         146 :       p++; lp--;  /* skip anchor character */
     640             :     }
     641         187 :     prepstate(&ms, L, s, ls, p, lp);
     642             :     do {
     643             :       const char *res;
     644        3519 :       reprepstate(&ms);
     645        3519 :       if ((res=match(&ms, s1, p)) != NULL) {
     646         151 :         if (find) {
     647         131 :           lua_pushinteger(L, (s1 - s) + 1);  /* start */
     648         131 :           lua_pushinteger(L, res - s);   /* end */
     649         151 :           return push_captures(&ms, NULL, 0) + 2;
     650             :         }
     651             :         else
     652          20 :           return push_captures(&ms, s1, res);
     653             :       }
     654        3368 :     } while (s1++ < ms.src_end && !anchor);
     655             :   }
     656          42 :   lua_pushnil(L);  /* not found */
     657          42 :   return 1;
     658             : }
     659             : 
     660             : 
     661         209 : static int str_find (lua_State *L) {
     662         209 :   return str_find_aux(L, 1);
     663             : }
     664             : 
     665             : 
     666          31 : static int str_match (lua_State *L) {
     667          31 :   return str_find_aux(L, 0);
     668             : }
     669             : 
     670             : 
     671             : /* state for 'gmatch' */
     672             : typedef struct GMatchState {
     673             :   const char *src;  /* current position */
     674             :   const char *p;  /* pattern */
     675             :   const char *lastmatch;  /* end of last match */
     676             :   MatchState ms;  /* match state */
     677             : } GMatchState;
     678             : 
     679             : 
     680          20 : static int gmatch_aux (lua_State *L) {
     681          20 :   GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3));
     682             :   const char *src;
     683          20 :   gm->ms.L = L;
     684          52 :   for (src = gm->src; src <= gm->ms.src_end; src++) {
     685             :     const char *e;
     686          48 :     reprepstate(&gm->ms);
     687          48 :     if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) {
     688          16 :       gm->src = gm->lastmatch = e;
     689          16 :       return push_captures(&gm->ms, src, e);
     690             :     }
     691             :   }
     692           4 :   return 0;  /* not found */
     693             : }
     694             : 
     695             : 
     696           4 : static int gmatch (lua_State *L) {
     697             :   size_t ls, lp;
     698           4 :   const char *s = luaL_checklstring(L, 1, &ls);
     699           4 :   const char *p = luaL_checklstring(L, 2, &lp);
     700             :   GMatchState *gm;
     701           4 :   lua_settop(L, 2);  /* keep them on closure to avoid being collected */
     702           4 :   gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState));
     703           4 :   prepstate(&gm->ms, L, s, ls, p, lp);
     704           4 :   gm->src = s; gm->p = p; gm->lastmatch = NULL;
     705           4 :   lua_pushcclosure(L, gmatch_aux, 3);
     706           4 :   return 1;
     707             : }
     708             : 
     709             : 
     710        1923 : static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
     711             :                                                    const char *e) {
     712             :   size_t l, i;
     713        1923 :   lua_State *L = ms->L;
     714        1923 :   const char *news = lua_tolstring(L, 3, &l);
     715        6571 :   for (i = 0; i < l; i++) {
     716        4648 :     if (news[i] != L_ESC)
     717        4585 :       luaL_addchar(b, news[i]);
     718             :     else {
     719          63 :       i++;  /* skip ESC */
     720          63 :       if (!isdigit(uchar(news[i]))) {
     721           0 :         if (news[i] != L_ESC)
     722           0 :           luaL_error(L, "invalid use of '%c' in replacement string", L_ESC);
     723           0 :         luaL_addchar(b, news[i]);
     724             :       }
     725          63 :       else if (news[i] == '0')
     726           0 :           luaL_addlstring(b, s, e - s);
     727             :       else {
     728          63 :         push_onecapture(ms, news[i] - '1', s, e);
     729          63 :         luaL_tolstring(L, -1, NULL);  /* if number, convert it to string */
     730          63 :         lua_remove(L, -2);  /* remove original value */
     731          63 :         luaL_addvalue(b);  /* add capture to accumulated result */
     732             :       }
     733             :     }
     734             :   }
     735        1923 : }
     736             : 
     737             : 
     738        1937 : static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
     739             :                                        const char *e, int tr) {
     740        1937 :   lua_State *L = ms->L;
     741        1937 :   switch (tr) {
     742          14 :     case LUA_TFUNCTION: {
     743             :       int n;
     744          14 :       lua_pushvalue(L, 3);
     745          14 :       n = push_captures(ms, s, e);
     746          14 :       lua_call(L, n, 1);
     747          14 :       break;
     748             :     }
     749           0 :     case LUA_TTABLE: {
     750           0 :       push_onecapture(ms, 0, s, e);
     751           0 :       lua_gettable(L, 3);
     752           0 :       break;
     753             :     }
     754        1923 :     default: {  /* LUA_TNUMBER or LUA_TSTRING */
     755        1923 :       add_s(ms, b, s, e);
     756        1923 :       return;
     757             :     }
     758             :   }
     759          14 :   if (!lua_toboolean(L, -1)) {  /* nil or false? */
     760           0 :     lua_pop(L, 1);
     761           0 :     lua_pushlstring(L, s, e - s);  /* keep original text */
     762             :   }
     763          14 :   else if (!lua_isstring(L, -1))
     764           0 :     luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1));
     765          14 :   luaL_addvalue(b);  /* add result to accumulator */
     766             : }
     767             : 
     768             : 
     769        1911 : static int str_gsub (lua_State *L) {
     770             :   size_t srcl, lp;
     771        1911 :   const char *src = luaL_checklstring(L, 1, &srcl);  /* subject */
     772        1911 :   const char *p = luaL_checklstring(L, 2, &lp);  /* pattern */
     773        1911 :   const char *lastmatch = NULL;  /* end of last match */
     774        1911 :   int tr = lua_type(L, 3);  /* replacement type */
     775        1911 :   lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1);  /* max replacements */
     776        1911 :   int anchor = (*p == '^');
     777        1911 :   lua_Integer n = 0;  /* replacement count */
     778             :   MatchState ms;
     779             :   luaL_Buffer b;
     780        1911 :   luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
     781             :                    tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
     782             :                       "string/function/table expected");
     783        1911 :   luaL_buffinit(L, &b);
     784        1911 :   if (anchor) {
     785          63 :     p++; lp--;  /* skip anchor character */
     786             :   }
     787        1911 :   prepstate(&ms, L, src, srcl, p, lp);
     788        9591 :   while (n < max_s) {
     789             :     const char *e;
     790        9591 :     reprepstate(&ms);  /* (re)prepare state for new match */
     791        9591 :     if ((e = match(&ms, src, p)) != NULL && e != lastmatch) {  /* match? */
     792        1937 :       n++;
     793        1937 :       add_value(&ms, &b, src, e, tr);  /* add replacement to buffer */
     794        1937 :       src = lastmatch = e;
     795             :     }
     796        7654 :     else if (src < ms.src_end)  /* otherwise, skip one character */
     797        5806 :       luaL_addchar(&b, *src++);
     798        1848 :     else break;  /* end of subject */
     799        7743 :     if (anchor) break;
     800             :   }
     801        1911 :   luaL_addlstring(&b, src, ms.src_end-src);
     802        1911 :   luaL_pushresult(&b);
     803        1911 :   lua_pushinteger(L, n);  /* number of substitutions */
     804        1911 :   return 2;
     805             : }
     806             : 
     807             : /* }====================================================== */
     808             : 
     809             : 
     810             : 
     811             : /*
     812             : ** {======================================================
     813             : ** STRING FORMAT
     814             : ** =======================================================
     815             : */
     816             : 
     817             : #if !defined(lua_number2strx)   /* { */
     818             : 
     819             : /*
     820             : ** Hexadecimal floating-point formatter
     821             : */
     822             : 
     823             : #include <math.h>
     824             : 
     825             : #define SIZELENMOD      (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char))
     826             : 
     827             : 
     828             : /*
     829             : ** Number of bits that goes into the first digit. It can be any value
     830             : ** between 1 and 4; the following definition tries to align the number
     831             : ** to nibble boundaries by making what is left after that first digit a
     832             : ** multiple of 4.
     833             : */
     834             : #define L_NBFD          ((l_mathlim(MANT_DIG) - 1)%4 + 1)
     835             : 
     836             : 
     837             : /*
     838             : ** Add integer part of 'x' to buffer and return new 'x'
     839             : */
     840             : static lua_Number adddigit (char *buff, int n, lua_Number x) {
     841             :   lua_Number dd = l_mathop(floor)(x);  /* get integer part from 'x' */
     842             :   int d = (int)dd;
     843             :   buff[n] = (d < 10 ? d + '0' : d - 10 + 'a');  /* add to buffer */
     844             :   return x - dd;  /* return what is left */
     845             : }
     846             : 
     847             : 
     848             : static int num2straux (char *buff, int sz, lua_Number x) {
     849             :   /* if 'inf' or 'NaN', format it like '%g' */
     850             :   if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL)
     851             :     return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x);
     852             :   else if (x == 0) {  /* can be -0... */
     853             :     /* create "0" or "-0" followed by exponent */
     854             :     return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x);
     855             :   }
     856             :   else {
     857             :     int e;
     858             :     lua_Number m = l_mathop(frexp)(x, &e);  /* 'x' fraction and exponent */
     859             :     int n = 0;  /* character count */
     860             :     if (m < 0) {  /* is number negative? */
     861             :       buff[n++] = '-';  /* add signal */
     862             :       m = -m;  /* make it positive */
     863             :     }
     864             :     buff[n++] = '0'; buff[n++] = 'x';  /* add "0x" */
     865             :     m = adddigit(buff, n++, m * (1 << L_NBFD));  /* add first digit */
     866             :     e -= L_NBFD;  /* this digit goes before the radix point */
     867             :     if (m > 0) {  /* more digits? */
     868             :       buff[n++] = lua_getlocaledecpoint();  /* add radix point */
     869             :       do {  /* add as many digits as needed */
     870             :         m = adddigit(buff, n++, m * 16);
     871             :       } while (m > 0);
     872             :     }
     873             :     n += l_sprintf(buff + n, sz - n, "p%+d", e);  /* add exponent */
     874             :     lua_assert(n < sz);
     875             :     return n;
     876             :   }
     877             : }
     878             : 
     879             : 
     880             : static int lua_number2strx (lua_State *L, char *buff, int sz,
     881             :                             const char *fmt, lua_Number x) {
     882             :   int n = num2straux(buff, sz, x);
     883             :   if (fmt[SIZELENMOD] == 'A') {
     884             :     int i;
     885             :     for (i = 0; i < n; i++)
     886             :       buff[i] = toupper(uchar(buff[i]));
     887             :   }
     888             :   else if (fmt[SIZELENMOD] != 'a')
     889             :     return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
     890             :   return n;
     891             : }
     892             : 
     893             : #endif                          /* } */
     894             : 
     895             : 
     896             : /*
     897             : ** Maximum size of each formatted item. This maximum size is produced
     898             : ** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.',
     899             : ** and '\0') + number of decimal digits to represent maxfloat (which
     900             : ** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra
     901             : ** expenses", such as locale-dependent stuff)
     902             : */
     903             : #define MAX_ITEM        (120 + l_mathlim(MAX_10_EXP))
     904             : 
     905             : 
     906             : /* valid flags in a format specification */
     907             : #define FLAGS   "-+ #0"
     908             : 
     909             : /*
     910             : ** maximum size of each format specification (such as "%-099.99d")
     911             : */
     912             : #define MAX_FORMAT      32
     913             : 
     914             : 
     915           6 : static void addquoted (luaL_Buffer *b, const char *s, size_t len) {
     916           6 :   luaL_addchar(b, '"');
     917        4036 :   while (len--) {
     918        4030 :     if (*s == '"' || *s == '\\' || *s == '\n') {
     919           8 :       luaL_addchar(b, '\\');
     920           8 :       luaL_addchar(b, *s);
     921             :     }
     922        4022 :     else if (iscntrl(uchar(*s))) {
     923             :       char buff[10];
     924           2 :       if (!isdigit(uchar(*(s+1))))
     925           2 :         l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s));
     926             :       else
     927           0 :         l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s));
     928           2 :       luaL_addstring(b, buff);
     929             :     }
     930             :     else
     931        4020 :       luaL_addchar(b, *s);
     932        4030 :     s++;
     933             :   }
     934           6 :   luaL_addchar(b, '"');
     935           6 : }
     936             : 
     937             : 
     938             : /*
     939             : ** Ensures the 'buff' string uses a dot as the radix character.
     940             : */
     941           0 : static void checkdp (char *buff, int nb) {
     942           0 :   if (memchr(buff, '.', nb) == NULL) {  /* no dot? */
     943           0 :     char point = lua_getlocaledecpoint();  /* try locale point */
     944           0 :     char *ppoint = (char *)memchr(buff, point, nb);
     945           0 :     if (ppoint) *ppoint = '.';  /* change it to a dot */
     946             :   }
     947           0 : }
     948             : 
     949             : 
     950           6 : static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
     951           6 :   switch (lua_type(L, arg)) {
     952           6 :     case LUA_TSTRING: {
     953             :       size_t len;
     954           6 :       const char *s = lua_tolstring(L, arg, &len);
     955           6 :       addquoted(b, s, len);
     956           6 :       break;
     957             :     }
     958           0 :     case LUA_TNUMBER: {
     959           0 :       char *buff = luaL_prepbuffsize(b, MAX_ITEM);
     960             :       int nb;
     961           0 :       if (!lua_isinteger(L, arg)) {  /* float? */
     962           0 :         lua_Number n = lua_tonumber(L, arg);  /* write as hexa ('%a') */
     963           0 :         nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n);
     964           0 :         checkdp(buff, nb);  /* ensure it uses a dot */
     965             :       }
     966             :       else {  /* integers */
     967           0 :         lua_Integer n = lua_tointeger(L, arg);
     968           0 :         const char *format = (n == LUA_MININTEGER)  /* corner case? */
     969             :                            ? "0x%" LUA_INTEGER_FRMLEN "x"  /* use hexa */
     970           0 :                            : LUA_INTEGER_FMT;  /* else use default format */
     971           0 :         nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n);
     972             :       }
     973           0 :       luaL_addsize(b, nb);
     974           0 :       break;
     975             :     }
     976           0 :     case LUA_TNIL: case LUA_TBOOLEAN: {
     977           0 :       luaL_tolstring(L, arg, NULL);
     978           0 :       luaL_addvalue(b);
     979           0 :       break;
     980             :     }
     981           0 :     default: {
     982           0 :       luaL_argerror(L, arg, "value has no literal form");
     983             :     }
     984             :   }
     985           6 : }
     986             : 
     987             : 
     988       30217 : static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
     989       30217 :   const char *p = strfrmt;
     990       31497 :   while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++;  /* skip flags */
     991       30217 :   if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char))
     992           2 :     luaL_error(L, "invalid format (repeated flags)");
     993       30215 :   if (isdigit(uchar(*p))) p++;  /* skip width */
     994       30215 :   if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
     995       30215 :   if (*p == '.') {
     996       16945 :     p++;
     997       16945 :     if (isdigit(uchar(*p))) p++;  /* skip precision */
     998       16945 :     if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
     999             :   }
    1000       30215 :   if (isdigit(uchar(*p)))
    1001           8 :     luaL_error(L, "invalid format (width or precision too long)");
    1002       30207 :   *(form++) = '%';
    1003       30207 :   memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char));
    1004       30207 :   form += (p - strfrmt) + 1;
    1005       30207 :   *form = '\0';
    1006       30207 :   return p;
    1007             : }
    1008             : 
    1009             : 
    1010             : /*
    1011             : ** add length modifier into formats
    1012             : */
    1013       19826 : static void addlenmod (char *form, const char *lenmod) {
    1014       19826 :   size_t l = strlen(form);
    1015       19826 :   size_t lm = strlen(lenmod);
    1016       19826 :   char spec = form[l - 1];
    1017       19826 :   strcpy(form + l - 1, lenmod);
    1018       19826 :   form[l + lm - 1] = spec;
    1019       19826 :   form[l + lm] = '\0';
    1020       19826 : }
    1021             : 
    1022             : 
    1023       22033 : static int str_format (lua_State *L) {
    1024       22033 :   int top = lua_gettop(L);
    1025       22033 :   int arg = 1;
    1026             :   size_t sfl;
    1027       22033 :   const char *strfrmt = luaL_checklstring(L, arg, &sfl);
    1028       22033 :   const char *strfrmt_end = strfrmt+sfl;
    1029             :   luaL_Buffer b;
    1030       22033 :   luaL_buffinit(L, &b);
    1031      106292 :   while (strfrmt < strfrmt_end) {
    1032       84275 :     if (*strfrmt != L_ESC)
    1033       54054 :       luaL_addchar(&b, *strfrmt++);
    1034       30221 :     else if (*++strfrmt == L_ESC)
    1035           2 :       luaL_addchar(&b, *strfrmt++);  /* %% */
    1036             :     else { /* format item */
    1037             :       char form[MAX_FORMAT];  /* to store the format ('%...') */
    1038       30219 :       char *buff = luaL_prepbuffsize(&b, MAX_ITEM);  /* to put formatted item */
    1039       30219 :       int nb = 0;  /* number of bytes in added item */
    1040       30219 :       if (++arg > top)
    1041           2 :         luaL_argerror(L, arg, "no value");
    1042       30217 :       strfrmt = scanformat(L, strfrmt, form);
    1043       30207 :       switch (*strfrmt++) {
    1044          20 :         case 'c': {
    1045          20 :           nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg));
    1046          20 :           break;
    1047             :         }
    1048        1931 :         case 'd': case 'i':
    1049             :         case 'o': case 'u': case 'x': case 'X': {
    1050        1931 :           lua_Integer n = luaL_checkinteger(L, arg);
    1051        1931 :           addlenmod(form, LUA_INTEGER_FRMLEN);
    1052        1931 :           nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n);
    1053        1931 :           break;
    1054             :         }
    1055          70 :         case 'a': case 'A':
    1056          70 :           addlenmod(form, LUA_NUMBER_FRMLEN);
    1057          70 :           nb = lua_number2strx(L, buff, MAX_ITEM, form,
    1058             :                                   luaL_checknumber(L, arg));
    1059          70 :           break;
    1060       17825 :         case 'e': case 'E': case 'f':
    1061             :         case 'g': case 'G': {
    1062       17825 :           lua_Number n = luaL_checknumber(L, arg);
    1063       17825 :           addlenmod(form, LUA_NUMBER_FRMLEN);
    1064       17825 :           nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n);
    1065       17825 :           break;
    1066             :         }
    1067           6 :         case 'q': {
    1068           6 :           addliteral(L, &b, arg);
    1069           6 :           break;
    1070             :         }
    1071       10353 :         case 's': {
    1072             :           size_t l;
    1073       10353 :           const char *s = luaL_tolstring(L, arg, &l);
    1074       10353 :           if (form[2] == '\0')  /* no modifiers? */
    1075       10339 :             luaL_addvalue(&b);  /* keep entire string */
    1076             :           else {
    1077          14 :             luaL_argcheck(L, l == strlen(s), arg, "string contains zeros");
    1078          12 :             if (!strchr(form, '.') && l >= 100) {
    1079             :               /* no precision and string is too long to be formatted */
    1080           2 :               luaL_addvalue(&b);  /* keep entire string */
    1081             :             }
    1082             :             else {  /* format the string into 'buff' */
    1083          10 :               nb = l_sprintf(buff, MAX_ITEM, form, s);
    1084          10 :               lua_pop(L, 1);  /* remove result from 'luaL_tolstring' */
    1085             :             }
    1086             :           }
    1087       10351 :           break;
    1088             :         }
    1089           2 :         default: {  /* also treat cases 'pnLlh' */
    1090           0 :           return luaL_error(L, "invalid option '%%%c' to 'format'",
    1091           2 :                                *(strfrmt - 1));
    1092             :         }
    1093             :       }
    1094             :       lua_assert(nb < MAX_ITEM);
    1095       30203 :       luaL_addsize(&b, nb);
    1096             :     }
    1097             :   }
    1098       22017 :   luaL_pushresult(&b);
    1099       22017 :   return 1;
    1100             : }
    1101             : 
    1102             : /* }====================================================== */
    1103             : 
    1104             : 
    1105             : /*
    1106             : ** {======================================================
    1107             : ** PACK/UNPACK
    1108             : ** =======================================================
    1109             : */
    1110             : 
    1111             : 
    1112             : /* value used for padding */
    1113             : #if !defined(LUAL_PACKPADBYTE)
    1114             : #define LUAL_PACKPADBYTE                0x00
    1115             : #endif
    1116             : 
    1117             : /* maximum size for the binary representation of an integer */
    1118             : #define MAXINTSIZE      16
    1119             : 
    1120             : /* number of bits in a character */
    1121             : #define NB      CHAR_BIT
    1122             : 
    1123             : /* mask for one character (NB 1's) */
    1124             : #define MC      ((1 << NB) - 1)
    1125             : 
    1126             : /* size of a lua_Integer */
    1127             : #define SZINT   ((int)sizeof(lua_Integer))
    1128             : 
    1129             : 
    1130             : /* dummy union to get native endianness */
    1131             : static const union {
    1132             :   int dummy;
    1133             :   char little;  /* true iff machine is little endian */
    1134             : } nativeendian = {1};
    1135             : 
    1136             : 
    1137             : /* dummy structure to get native alignment requirements */
    1138             : struct cD {
    1139             :   char c;
    1140             :   union { double d; void *p; lua_Integer i; lua_Number n; } u;
    1141             : };
    1142             : 
    1143             : #define MAXALIGN        (offsetof(struct cD, u))
    1144             : 
    1145             : 
    1146             : /*
    1147             : ** Union for serializing floats
    1148             : */
    1149             : typedef union Ftypes {
    1150             :   float f;
    1151             :   double d;
    1152             :   lua_Number n;
    1153             :   char buff[5 * sizeof(lua_Number)];  /* enough for any float type */
    1154             : } Ftypes;
    1155             : 
    1156             : 
    1157             : /*
    1158             : ** information to pack/unpack stuff
    1159             : */
    1160             : typedef struct Header {
    1161             :   lua_State *L;
    1162             :   int islittle;
    1163             :   int maxalign;
    1164             : } Header;
    1165             : 
    1166             : 
    1167             : /*
    1168             : ** options for pack/unpack
    1169             : */
    1170             : typedef enum KOption {
    1171             :   Kint,         /* signed integers */
    1172             :   Kuint,        /* unsigned integers */
    1173             :   Kfloat,       /* floating-point numbers */
    1174             :   Kchar,        /* fixed-length strings */
    1175             :   Kstring,      /* strings with prefixed length */
    1176             :   Kzstr,        /* zero-terminated strings */
    1177             :   Kpadding,     /* padding */
    1178             :   Kpaddalign,   /* padding for alignment */
    1179             :   Knop          /* no-op (configuration or spaces) */
    1180             : } KOption;
    1181             : 
    1182             : 
    1183             : /*
    1184             : ** Read an integer numeral from string 'fmt' or return 'df' if
    1185             : ** there is no numeral
    1186             : */
    1187          85 : static int digit (int c) { return '0' <= c && c <= '9'; }
    1188             : 
    1189          35 : static int getnum (const char **fmt, int df) {
    1190          35 :   if (!digit(**fmt))  /* no number? */
    1191           2 :     return df;  /* return default value */
    1192             :   else {
    1193          33 :     int a = 0;
    1194             :     do {
    1195          50 :       a = a*10 + (*((*fmt)++) - '0');
    1196          50 :     } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10);
    1197          33 :     return a;
    1198             :   }
    1199             : }
    1200             : 
    1201             : 
    1202             : /*
    1203             : ** Read an integer numeral and raises an error if it is larger
    1204             : ** than the maximum size for integers.
    1205             : */
    1206          18 : static int getnumlimit (Header *h, const char **fmt, int df) {
    1207          18 :   int sz = getnum(fmt, df);
    1208          18 :   if (sz > MAXINTSIZE || sz <= 0)
    1209           0 :     return luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
    1210             :                             sz, MAXINTSIZE);
    1211          18 :   return sz;
    1212             : }
    1213             : 
    1214             : 
    1215             : /*
    1216             : ** Initialize Header
    1217             : */
    1218          46 : static void initheader (lua_State *L, Header *h) {
    1219          46 :   h->L = L;
    1220          46 :   h->islittle = nativeendian.little;
    1221          46 :   h->maxalign = 1;
    1222          46 : }
    1223             : 
    1224             : 
    1225             : /*
    1226             : ** Read and classify next option. 'size' is filled with option's size.
    1227             : */
    1228         167 : static KOption getoption (Header *h, const char **fmt, int *size) {
    1229         167 :   int opt = *((*fmt)++);
    1230         167 :   *size = 0;  /* default */
    1231         167 :   switch (opt) {
    1232           0 :     case 'b': *size = sizeof(char); return Kint;
    1233          63 :     case 'B': *size = sizeof(char); return Kuint;
    1234           2 :     case 'h': *size = sizeof(short); return Kint;
    1235           2 :     case 'H': *size = sizeof(short); return Kuint;
    1236           0 :     case 'l': *size = sizeof(long); return Kint;
    1237           0 :     case 'L': *size = sizeof(long); return Kuint;
    1238           0 :     case 'j': *size = sizeof(lua_Integer); return Kint;
    1239           0 :     case 'J': *size = sizeof(lua_Integer); return Kuint;
    1240           0 :     case 'T': *size = sizeof(size_t); return Kuint;
    1241          21 :     case 'f': *size = sizeof(float); return Kfloat;
    1242           0 :     case 'd': *size = sizeof(double); return Kfloat;
    1243           0 :     case 'n': *size = sizeof(lua_Number); return Kfloat;
    1244           4 :     case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint;
    1245          14 :     case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
    1246           0 :     case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
    1247          17 :     case 'c':
    1248          17 :       *size = getnum(fmt, -1);
    1249          17 :       if (*size == -1)
    1250           0 :         luaL_error(h->L, "missing size for format option 'c'");
    1251          17 :       return Kchar;
    1252           0 :     case 'z': return Kzstr;
    1253           0 :     case 'x': *size = 1; return Kpadding;
    1254           0 :     case 'X': return Kpaddalign;
    1255           0 :     case ' ': break;
    1256          44 :     case '<': h->islittle = 1; break;
    1257           0 :     case '>': h->islittle = 0; break;
    1258           0 :     case '=': h->islittle = nativeendian.little; break;
    1259           0 :     case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break;
    1260           0 :     default: luaL_error(h->L, "invalid format option '%c'", opt);
    1261             :   }
    1262          44 :   return Knop;
    1263             : }
    1264             : 
    1265             : 
    1266             : /*
    1267             : ** Read, classify, and fill other details about the next option.
    1268             : ** 'psize' is filled with option's size, 'notoalign' with its
    1269             : ** alignment requirements.
    1270             : ** Local variable 'size' gets the size to be aligned. (Kpadal option
    1271             : ** always gets its full alignment, other options are limited by
    1272             : ** the maximum alignment ('maxalign'). Kchar option needs no alignment
    1273             : ** despite its size.
    1274             : */
    1275         167 : static KOption getdetails (Header *h, size_t totalsize,
    1276             :                            const char **fmt, int *psize, int *ntoalign) {
    1277         167 :   KOption opt = getoption(h, fmt, psize);
    1278         167 :   int align = *psize;  /* usually, alignment follows size */
    1279         167 :   if (opt == Kpaddalign) {  /* 'X' gets alignment from following option */
    1280           0 :     if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0)
    1281           0 :       luaL_argerror(h->L, 1, "invalid next option for option 'X'");
    1282             :   }
    1283         167 :   if (align <= 1 || opt == Kchar)  /* need no alignment? */
    1284         124 :     *ntoalign = 0;
    1285             :   else {
    1286          43 :     if (align > h->maxalign)  /* enforce maximum alignment */
    1287          43 :       align = h->maxalign;
    1288          43 :     if ((align & (align - 1)) != 0)  /* is 'align' not a power of 2? */
    1289           0 :       luaL_argerror(h->L, 1, "format asks for alignment not power of 2");
    1290          43 :     *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1);
    1291             :   }
    1292         167 :   return opt;
    1293             : }
    1294             : 
    1295             : 
    1296             : /*
    1297             : ** Pack integer 'n' with 'size' bytes and 'islittle' endianness.
    1298             : ** The final 'if' handles the case when 'size' is larger than
    1299             : ** the size of a Lua integer, correcting the extra sign-extension
    1300             : ** bytes if necessary (by default they would be zeros).
    1301             : */
    1302          23 : static void packint (luaL_Buffer *b, lua_Unsigned n,
    1303             :                      int islittle, int size, int neg) {
    1304          23 :   char *buff = luaL_prepbuffsize(b, size);
    1305             :   int i;
    1306          23 :   buff[islittle ? 0 : size - 1] = (char)(n & MC);  /* first byte */
    1307          61 :   for (i = 1; i < size; i++) {
    1308          38 :     n >>= NB;
    1309          38 :     buff[islittle ? i : size - 1 - i] = (char)(n & MC);
    1310             :   }
    1311          23 :   if (neg && size > SZINT) {  /* negative number need sign extension? */
    1312           0 :     for (i = SZINT; i < size; i++)  /* correct extra bytes */
    1313           0 :       buff[islittle ? i : size - 1 - i] = (char)MC;
    1314             :   }
    1315          23 :   luaL_addsize(b, size);  /* add result to buffer */
    1316          23 : }
    1317             : 
    1318             : 
    1319             : /*
    1320             : ** Copy 'size' bytes from 'src' to 'dest', correcting endianness if
    1321             : ** given 'islittle' is different from native endianness.
    1322             : */
    1323          21 : static void copywithendian (volatile char *dest, volatile const char *src,
    1324             :                             int size, int islittle) {
    1325          21 :   if (islittle == nativeendian.little) {
    1326         105 :     while (size-- != 0)
    1327          84 :       *(dest++) = *(src++);
    1328             :   }
    1329             :   else {
    1330           0 :     dest += size - 1;
    1331           0 :     while (size-- != 0)
    1332           0 :       *(dest--) = *(src++);
    1333             :   }
    1334          21 : }
    1335             : 
    1336             : 
    1337          10 : static int str_pack (lua_State *L) {
    1338             :   luaL_Buffer b;
    1339             :   Header h;
    1340          10 :   const char *fmt = luaL_checkstring(L, 1);  /* format string */
    1341          10 :   int arg = 1;  /* current argument to pack */
    1342          10 :   size_t totalsize = 0;  /* accumulate total size of result */
    1343          10 :   initheader(L, &h);
    1344          10 :   lua_pushnil(L);  /* mark to separate arguments from string buffer */
    1345          10 :   luaL_buffinit(L, &b);
    1346          65 :   while (*fmt != '\0') {
    1347             :     int size, ntoalign;
    1348          55 :     KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
    1349          55 :     totalsize += ntoalign + size;
    1350          55 :     while (ntoalign-- > 0)
    1351           0 :      luaL_addchar(&b, LUAL_PACKPADBYTE);  /* fill alignment */
    1352          55 :     arg++;
    1353          55 :     switch (opt) {
    1354           4 :       case Kint: {  /* signed integers */
    1355           4 :         lua_Integer n = luaL_checkinteger(L, arg);
    1356           4 :         if (size < SZINT) {  /* need overflow check? */
    1357           2 :           lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1);
    1358           2 :           luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow");
    1359             :         }
    1360           4 :         packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0));
    1361           4 :         break;
    1362             :       }
    1363          19 :       case Kuint: {  /* unsigned integers */
    1364          19 :         lua_Integer n = luaL_checkinteger(L, arg);
    1365          19 :         if (size < SZINT)  /* need overflow check? */
    1366          11 :           luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)),
    1367             :                            arg, "unsigned overflow");
    1368          19 :         packint(&b, (lua_Unsigned)n, h.islittle, size, 0);
    1369          19 :         break;
    1370             :       }
    1371          13 :       case Kfloat: {  /* floating-point options */
    1372             :         volatile Ftypes u;
    1373          13 :         char *buff = luaL_prepbuffsize(&b, size);
    1374          13 :         lua_Number n = luaL_checknumber(L, arg);  /* get argument */
    1375          13 :         if (size == sizeof(u.f)) u.f = (float)n;  /* copy it into 'u' */
    1376           0 :         else if (size == sizeof(u.d)) u.d = (double)n;
    1377           0 :         else u.n = n;
    1378             :         /* move 'u' to final result, correcting endianness if needed */
    1379          13 :         copywithendian(buff, u.buff, size, h.islittle);
    1380          13 :         luaL_addsize(&b, size);
    1381          13 :         break;
    1382             :       }
    1383           9 :       case Kchar: {  /* fixed-size string */
    1384             :         size_t len;
    1385           9 :         const char *s = luaL_checklstring(L, arg, &len);
    1386           9 :         luaL_argcheck(L, len <= (size_t)size, arg,
    1387             :                          "string longer than given size");
    1388           9 :         luaL_addlstring(&b, s, len);  /* add string */
    1389          59 :         while (len++ < (size_t)size)  /* pad extra space */
    1390          50 :           luaL_addchar(&b, LUAL_PACKPADBYTE);
    1391           9 :         break;
    1392             :       }
    1393           0 :       case Kstring: {  /* strings with length count */
    1394             :         size_t len;
    1395           0 :         const char *s = luaL_checklstring(L, arg, &len);
    1396           0 :         luaL_argcheck(L, size >= (int)sizeof(size_t) ||
    1397             :                          len < ((size_t)1 << (size * NB)),
    1398             :                          arg, "string length does not fit in given size");
    1399           0 :         packint(&b, (lua_Unsigned)len, h.islittle, size, 0);  /* pack length */
    1400           0 :         luaL_addlstring(&b, s, len);
    1401           0 :         totalsize += len;
    1402           0 :         break;
    1403             :       }
    1404           0 :       case Kzstr: {  /* zero-terminated string */
    1405             :         size_t len;
    1406           0 :         const char *s = luaL_checklstring(L, arg, &len);
    1407           0 :         luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros");
    1408           0 :         luaL_addlstring(&b, s, len);
    1409           0 :         luaL_addchar(&b, '\0');  /* add zero at the end */
    1410           0 :         totalsize += len + 1;
    1411           0 :         break;
    1412             :       }
    1413           0 :       case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE);  /* FALLTHROUGH */
    1414          10 :       case Kpaddalign: case Knop:
    1415          10 :         arg--;  /* undo increment */
    1416          10 :         break;
    1417             :     }
    1418             :   }
    1419          10 :   luaL_pushresult(&b);
    1420          10 :   return 1;
    1421             : }
    1422             : 
    1423             : 
    1424           2 : static int str_packsize (lua_State *L) {
    1425             :   Header h;
    1426           2 :   const char *fmt = luaL_checkstring(L, 1);  /* format string */
    1427           2 :   size_t totalsize = 0;  /* accumulate total size of result */
    1428           2 :   initheader(L, &h);
    1429           4 :   while (*fmt != '\0') {
    1430             :     int size, ntoalign;
    1431           2 :     KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
    1432           2 :     size += ntoalign;  /* total space used by option */
    1433           2 :     luaL_argcheck(L, totalsize <= MAXSIZE - size, 1,
    1434             :                      "format result too large");
    1435           2 :     totalsize += size;
    1436           2 :     switch (opt) {
    1437           0 :       case Kstring:  /* strings with length count */
    1438             :       case Kzstr:    /* zero-terminated string */
    1439           0 :         luaL_argerror(L, 1, "variable-length format");
    1440             :         /* call never return, but to avoid warnings: *//* FALLTHROUGH */
    1441           2 :       default:  break;
    1442             :     }
    1443             :   }
    1444           2 :   lua_pushinteger(L, (lua_Integer)totalsize);
    1445           2 :   return 1;
    1446             : }
    1447             : 
    1448             : 
    1449             : /*
    1450             : ** Unpack an integer with 'size' bytes and 'islittle' endianness.
    1451             : ** If size is smaller than the size of a Lua integer and integer
    1452             : ** is signed, must do sign extension (propagating the sign to the
    1453             : ** higher bits); if size is larger than the size of a Lua integer,
    1454             : ** it must check the unread bytes to see whether they do not cause an
    1455             : ** overflow.
    1456             : */
    1457          60 : static lua_Integer unpackint (lua_State *L, const char *str,
    1458             :                               int islittle, int size, int issigned) {
    1459          60 :   lua_Unsigned res = 0;
    1460             :   int i;
    1461          60 :   int limit = (size  <= SZINT) ? size : SZINT;
    1462         132 :   for (i = limit - 1; i >= 0; i--) {
    1463          72 :     res <<= NB;
    1464          72 :     res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i];
    1465             :   }
    1466          60 :   if (size < SZINT) {  /* real size smaller than lua_Integer? */
    1467          58 :     if (issigned) {  /* needs sign extension? */
    1468           0 :       lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1);
    1469           0 :       res = ((res ^ mask) - mask);  /* do sign extension */
    1470             :     }
    1471             :   }
    1472           2 :   else if (size > SZINT) {  /* must check unread bytes */
    1473           0 :     int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC;
    1474           0 :     for (i = limit; i < size; i++) {
    1475           0 :       if ((unsigned char)str[islittle ? i : size - 1 - i] != mask)
    1476           0 :         luaL_error(L, "%d-byte integer does not fit into Lua Integer", size);
    1477             :     }
    1478             :   }
    1479          60 :   return (lua_Integer)res;
    1480             : }
    1481             : 
    1482             : 
    1483          34 : static int str_unpack (lua_State *L) {
    1484             :   Header h;
    1485          34 :   const char *fmt = luaL_checkstring(L, 1);
    1486             :   size_t ld;
    1487          34 :   const char *data = luaL_checklstring(L, 2, &ld);
    1488          34 :   size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1;
    1489          34 :   int n = 0;  /* number of results */
    1490          34 :   luaL_argcheck(L, pos <= ld, 3, "initial position out of string");
    1491          34 :   initheader(L, &h);
    1492         144 :   while (*fmt != '\0') {
    1493             :     int size, ntoalign;
    1494         110 :     KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign);
    1495         110 :     if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld)
    1496           0 :       luaL_argerror(L, 2, "data string too short");
    1497         110 :     pos += ntoalign;  /* skip alignment */
    1498             :     /* stack space for item + next position */
    1499         110 :     luaL_checkstack(L, 2, "too many results");
    1500         110 :     n++;
    1501         110 :     switch (opt) {
    1502          60 :       case Kint:
    1503             :       case Kuint: {
    1504          60 :         lua_Integer res = unpackint(L, data + pos, h.islittle, size,
    1505             :                                        (opt == Kint));
    1506          60 :         lua_pushinteger(L, res);
    1507          60 :         break;
    1508             :       }
    1509           8 :       case Kfloat: {
    1510             :         volatile Ftypes u;
    1511             :         lua_Number num;
    1512           8 :         copywithendian(u.buff, data + pos, size, h.islittle);
    1513           8 :         if (size == sizeof(u.f)) num = (lua_Number)u.f;
    1514           0 :         else if (size == sizeof(u.d)) num = (lua_Number)u.d;
    1515           0 :         else num = u.n;
    1516           8 :         lua_pushnumber(L, num);
    1517           8 :         break;
    1518             :       }
    1519           8 :       case Kchar: {
    1520           8 :         lua_pushlstring(L, data + pos, size);
    1521           8 :         break;
    1522             :       }
    1523           0 :       case Kstring: {
    1524           0 :         size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0);
    1525           0 :         luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short");
    1526           0 :         lua_pushlstring(L, data + pos + size, len);
    1527           0 :         pos += len;  /* skip string */
    1528           0 :         break;
    1529             :       }
    1530           0 :       case Kzstr: {
    1531           0 :         size_t len = (int)strlen(data + pos);
    1532           0 :         lua_pushlstring(L, data + pos, len);
    1533           0 :         pos += len + 1;  /* skip string plus final '\0' */
    1534           0 :         break;
    1535             :       }
    1536          34 :       case Kpaddalign: case Kpadding: case Knop:
    1537          34 :         n--;  /* undo increment */
    1538          34 :         break;
    1539             :     }
    1540         110 :     pos += size;
    1541             :   }
    1542          34 :   lua_pushinteger(L, pos + 1);  /* next position */
    1543          34 :   return n + 1;
    1544             : }
    1545             : 
    1546             : /* }====================================================== */
    1547             : 
    1548             : 
    1549             : static const luaL_Reg strlib[] = {
    1550             :   {"byte", str_byte},
    1551             :   {"char", str_char},
    1552             : //  {"dump", str_dump},
    1553             :   {"find", str_find},
    1554             :   {"format", str_format},
    1555             :   {"gmatch", gmatch},
    1556             :   {"gsub", str_gsub},
    1557             :   {"len", str_len},
    1558             :   {"lower", str_lower},
    1559             :   {"match", str_match},
    1560             :   {"rep", str_rep},
    1561             :   {"reverse", str_reverse},
    1562             :   {"sub", str_sub},
    1563             :   {"upper", str_upper},
    1564             :   {"pack", str_pack},
    1565             :   {"packsize", str_packsize},
    1566             :   {"unpack", str_unpack},
    1567             :   {NULL, NULL}
    1568             : };
    1569             : 
    1570             : 
    1571           0 : static void createmetatable (lua_State *L) {
    1572           0 :   lua_createtable(L, 0, 1);  /* table to be metatable for strings */
    1573           0 :   lua_pushliteral(L, "");  /* dummy string */
    1574           0 :   lua_pushvalue(L, -2);  /* copy table */
    1575           0 :   lua_setmetatable(L, -2);  /* set table as metatable for strings */
    1576           0 :   lua_pop(L, 1);  /* pop dummy string */
    1577           0 :   lua_pushvalue(L, -2);  /* get string library */
    1578           0 :   lua_setfield(L, -2, "__index");  /* metatable.__index = string */
    1579           0 :   lua_pop(L, 1);  /* pop metatable */
    1580           0 : }
    1581             : 
    1582             : 
    1583             : /*
    1584             : ** Open string library
    1585             : */
    1586         189 : LUAMOD_API int luaopen_string (lua_State *L) {
    1587         189 :   luaL_newlib(L, strlib);
    1588             : #if defined(ARDUPILOT_BUILD)
    1589             :   // metatable setup handled by Ardupilot scripting system
    1590             : #else
    1591             :   createmetatable(L);
    1592             : #endif
    1593         189 :   return 1;
    1594             : }
    1595             : 

Generated by: LCOV version 1.14