LCOV - code coverage report
Current view: directory - src - lstrlib.c Found Hit Coverage
Test: Lua 5.1.4 Lines: 465 425 91.4 %
Date: 2009-09-13
Colors: not hit hit

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

Generated by: LCOV version 1.7