LCOV - code coverage report
Current view: top level - src - lstrlib.c Coverage Total Hit
Test: Lua 5.1.5 Lines: 99.0 % 502 497
Test Date: 2024-04-28 10:23:09
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              : ** $Id: lstrlib.c,v 1.132.1.5 2010/05/14 15:34:19 roberto Exp $
       3              : ** Standard library for string operations and pattern-matching
       4              : ** See Copyright Notice in lua.h
       5              : */
       6              : 
       7              : 
       8              : #include <ctype.h>
       9              : #include <stddef.h>
      10              : #include <stdio.h>
      11              : #include <stdlib.h>
      12              : #include <string.h>
      13              : 
      14              : #define lstrlib_c
      15              : #define LUA_LIB
      16              : 
      17              : #include "lua.h"
      18              : 
      19              : #include "lauxlib.h"
      20              : #include "lualib.h"
      21              : 
      22              : 
      23              : /* macro to `unsign' a character */
      24              : #define uchar(c)        ((unsigned char)(c))
      25              : 
      26              : 
      27              : 
      28          176 : static int str_len (lua_State *L) {
      29              :   size_t l;
      30          176 :   luaL_checklstring(L, 1, &l);
      31          176 :   lua_pushinteger(L, l);
      32          176 :   return 1;
      33              : }
      34              : 
      35              : 
      36        13274 : static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) {
      37              :   /* relative string position: negative means back from end */
      38        13274 :   if (pos < 0) pos += (ptrdiff_t)len + 1;
      39        13274 :   return (pos >= 0) ? pos : 0;
      40              : }
      41              : 
      42              : 
      43         6341 : static int str_sub (lua_State *L) {
      44              :   size_t l;
      45         6341 :   const char *s = luaL_checklstring(L, 1, &l);
      46         6341 :   ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l);
      47         6341 :   ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l);
      48         6341 :   if (start < 1) start = 1;
      49         6341 :   if (end > (ptrdiff_t)l) end = (ptrdiff_t)l;
      50         6341 :   if (start <= end)
      51         6177 :     lua_pushlstring(L, s+start-1, end-start+1);
      52          164 :   else lua_pushliteral(L, "");
      53         6341 :   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           22 :   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            3 : static int str_upper (lua_State *L) {
      82              :   size_t l;
      83              :   size_t i;
      84              :   luaL_Buffer b;
      85            3 :   const char *s = luaL_checklstring(L, 1, &l);
      86            3 :   luaL_buffinit(L, &b);
      87        40011 :   for (i=0; i<l; i++)
      88        40008 :     luaL_addchar(&b, toupper(uchar(s[i])));
      89            3 :   luaL_pushresult(&b);
      90            3 :   return 1;
      91              : }
      92              : 
      93            8 : static int str_rep (lua_State *L) {
      94              :   size_t l;
      95              :   luaL_Buffer b;
      96            8 :   const char *s = luaL_checklstring(L, 1, &l);
      97            8 :   int n = luaL_checkint(L, 2);
      98            8 :   luaL_buffinit(L, &b);
      99        20206 :   while (n-- > 0)
     100        20198 :     luaL_addlstring(&b, s, l);
     101            8 :   luaL_pushresult(&b);
     102            8 :   return 1;
     103              : }
     104              : 
     105              : 
     106           16 : static int str_byte (lua_State *L) {
     107              :   size_t l;
     108           16 :   const char *s = luaL_checklstring(L, 1, &l);
     109           16 :   ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l);
     110           16 :   ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l);
     111              :   int n, i;
     112           16 :   if (posi <= 0) posi = 1;
     113           16 :   if ((size_t)pose > l) pose = l;
     114           16 :   if (posi > pose) return 0;  /* empty interval; return no values */
     115           14 :   n = (int)(pose -  posi + 1);
     116           14 :   if (posi + n <= pose)  /* overflow? */
     117            0 :     luaL_error(L, "string slice too long");
     118           14 :   luaL_checkstack(L, n, "string slice too long");
     119           32 :   for (i=0; i<n; i++)
     120           18 :     lua_pushinteger(L, uchar(s[posi+i-1]));
     121           14 :   return n;
     122              : }
     123              : 
     124              : 
     125            9 : static int str_char (lua_State *L) {
     126            9 :   int n = lua_gettop(L);  /* number of arguments */
     127              :   int i;
     128              :   luaL_Buffer b;
     129            9 :   luaL_buffinit(L, &b);
     130           19 :   for (i=1; i<=n; i++) {
     131           12 :     int c = luaL_checkint(L, i);
     132           11 :     luaL_argcheck(L, uchar(c) == c, i, "invalid value");
     133           10 :     luaL_addchar(&b, uchar(c));
     134              :   }
     135            7 :   luaL_pushresult(&b);
     136            7 :   return 1;
     137              : }
     138              : 
     139              : 
     140           25 : static int writer (lua_State *L, const void* b, size_t size, void* B) {
     141              :   (void)L;
     142           25 :   luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);
     143           25 :   return 0;
     144              : }
     145              : 
     146              : 
     147            2 : static int str_dump (lua_State *L) {
     148              :   luaL_Buffer b;
     149            2 :   luaL_checktype(L, 1, LUA_TFUNCTION);
     150            2 :   lua_settop(L, 1);
     151            2 :   luaL_buffinit(L,&b);
     152            2 :   if (lua_dump(L, writer, &b) != 0)
     153            1 :     luaL_error(L, "unable to dump given function");
     154            1 :   luaL_pushresult(&b);
     155            1 :   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           24 : static int check_capture (MatchState *ms, int l) {
     187           24 :   l -= '1';
     188           24 :   if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
     189            1 :     return luaL_error(ms->L, "invalid capture index");
     190           23 :   return l;
     191              : }
     192              : 
     193              : 
     194          132 : static int capture_to_close (MatchState *ms) {
     195          132 :   int level = ms->level;
     196          139 :   for (level--; level>=0; level--)
     197          138 :     if (ms->capture[level].len == CAP_UNFINISHED) return level;
     198            1 :   return luaL_error(ms->L, "invalid pattern capture");
     199              : }
     200              : 
     201              : 
     202        13907 : static const char *classend (MatchState *ms, const char *p) {
     203        13907 :   switch (*p++) {
     204         1025 :     case L_ESC: {
     205         1025 :       if (*p == '\0')
     206            1 :         luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")");
     207         1024 :       return p+1;
     208              :     }
     209          492 :     case '[': {
     210          492 :       if (*p == '^') p++;
     211              :       do {  /* look for a `]' */
     212          829 :         if (*p == '\0')
     213            3 :           luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")");
     214          826 :         if (*(p++) == L_ESC && *p != '\0')
     215          104 :           p++;  /* skip escapes (e.g. `%]') */
     216          826 :       } while (*p != ']');
     217          489 :       return p+1;
     218              :     }
     219        12390 :     default: {
     220        12390 :       return p;
     221              :     }
     222              :   }
     223              : }
     224              : 
     225              : 
     226         2869 : static int match_class (int c, int cl) {
     227              :   int res;
     228         2869 :   switch (tolower(cl)) {
     229          111 :     case 'a' : res = isalpha(c); break;
     230           13 :     case 'c' : res = iscntrl(c); break;
     231         1207 :     case 'd' : res = isdigit(c); break;
     232           14 :     case 'l' : res = islower(c); break;
     233           14 :     case 'p' : res = ispunct(c); break;
     234          103 :     case 's' : res = isspace(c); break;
     235           14 :     case 'u' : res = isupper(c); break;
     236          791 :     case 'w' : res = isalnum(c); break;
     237          203 :     case 'x' : res = isxdigit(c); break;
     238           11 :     case 'z' : res = (c == 0); break;
     239          388 :     default: return (cl == c);
     240              :   }
     241         2481 :   return (islower(cl) ? res : !res);
     242              : }
     243              : 
     244              : 
     245         4319 : static int matchbracketclass (int c, const char *p, const char *ec) {
     246         4319 :   int sig = 1;
     247         4319 :   if (*(p+1) == '^') {
     248         4109 :     sig = 0;
     249         4109 :     p++;  /* skip the `^' */
     250              :   }
     251         8457 :   while (++p < ec) {
     252         4577 :     if (*p == L_ESC) {
     253          183 :       p++;
     254          183 :       if (match_class(c, uchar(*p)))
     255          104 :         return sig;
     256              :     }
     257         4394 :     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         4351 :     else if (uchar(*p) == c) return sig;
     263              :   }
     264         3880 :   return !sig;
     265              : }
     266              : 
     267              : 
     268        19632 : static int singlematch (int c, const char *p, const char *ep) {
     269        19632 :   switch (*p) {
     270          426 :     case '.': return 1;  /* matches any char */
     271         2686 :     case L_ESC: return match_class(c, uchar(*(p+1)));
     272         4269 :     case '[': return matchbracketclass(c, p, ep-1);
     273        12251 :     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           15 : static const char *matchbalance (MatchState *ms, const char *s,
     282              :                                    const char *p) {
     283           15 :   if (*p == 0 || *(p+1) == 0)
     284            1 :     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           54 :     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          790 : static const char *max_expand (MatchState *ms, const char *s,
     302              :                                  const char *p, const char *ep) {
     303          790 :   ptrdiff_t i = 0;  /* counts maximum expand for item */
     304         5567 :   while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep))
     305         4777 :     i++;
     306              :   /* keeps trying to match with the maximum repetitions */
     307          859 :   while (i>=0) {
     308          836 :     const char *res = match(ms, (s+i), ep+1);
     309          836 :     if (res) return res;
     310           69 :     i--;  /* else didn't match; reduce 1 repetition to try again */
     311              :   }
     312           23 :   return NULL;
     313              : }
     314              : 
     315              : 
     316           38 : static const char *min_expand (MatchState *ms, const char *s,
     317              :                                  const char *p, const char *ep) {
     318          371 :   for (;;) {
     319          409 :     const char *res = match(ms, s, ep+1);
     320          409 :     if (res != NULL)
     321           38 :       return res;
     322          371 :     else if (s<ms->src_end && singlematch(uchar(*s), p, ep))
     323          371 :       s++;  /* try with one more repetition */
     324            0 :     else return NULL;
     325              :   }
     326              : }
     327              : 
     328              : 
     329          116 : static const char *start_capture (MatchState *ms, const char *s,
     330              :                                     const char *p, int what) {
     331              :   const char *res;
     332          116 :   int level = ms->level;
     333          116 :   if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures");
     334          116 :   ms->capture[level].init = s;
     335          116 :   ms->capture[level].len = what;
     336          116 :   ms->level = level+1;
     337          116 :   if ((res=match(ms, s, p)) == NULL)  /* match failed? */
     338           43 :     ms->level--;  /* undo capture */
     339          116 :   return res;
     340              : }
     341              : 
     342              : 
     343          132 : static const char *end_capture (MatchState *ms, const char *s,
     344              :                                   const char *p) {
     345          132 :   int l = capture_to_close(ms);
     346              :   const char *res;
     347          131 :   ms->capture[l].len = s - ms->capture[l].init;  /* close capture */
     348          131 :   if ((res = match(ms, s, p)) == NULL)  /* match failed? */
     349           60 :     ms->capture[l].len = CAP_UNFINISHED;  /* undo capture */
     350          131 :   return res;
     351              : }
     352              : 
     353              : 
     354           24 : static const char *match_capture (MatchState *ms, const char *s, int l) {
     355              :   size_t len;
     356           24 :   l = check_capture(ms, l);
     357           23 :   len = ms->capture[l].len;
     358           23 :   if ((size_t)(ms->src_end-s) >= len &&
     359           23 :       memcmp(ms->capture[l].init, s, len) == 0)
     360            5 :     return s+len;
     361           18 :   else return NULL;
     362              : }
     363              : 
     364              : 
     365         3697 : static const char *match (MatchState *ms, const char *s, const char *p) {
     366        11077 :   init: /* using goto's to optimize tail recursion */
     367        14774 :   switch (*p) {
     368          116 :     case '(': {  /* start capture */
     369          116 :       if (*(p+1) == ')')  /* position capture? */
     370            4 :         return start_capture(ms, s, p+2, CAP_POSITION);
     371              :       else
     372          112 :         return start_capture(ms, s, p+1, CAP_UNFINISHED);
     373              :     }
     374          132 :     case ')': {  /* end capture */
     375          132 :       return end_capture(ms, s, p+1);
     376              :     }
     377         1099 :     case L_ESC: {
     378         1099 :       switch (*(p+1)) {
     379           15 :         case 'b': {  /* balanced string? */
     380           15 :           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           35 :         case 'f': {  /* frontier? */
     385              :           const char *ep; char previous;
     386           35 :           p += 2;
     387           35 :           if (*p != '[')
     388            1 :             luaL_error(ms->L, "missing " LUA_QL("[") " after "
     389              :                                LUA_QL("%%f") " in pattern");
     390           34 :           ep = classend(ms, p);  /* points to what is next */
     391           34 :           previous = (s == ms->src_init) ? '\0' : *(s-1);
     392           50 :           if (matchbracketclass(uchar(previous), p, ep-1) ||
     393           44 :              !matchbracketclass(uchar(*s), p, ep-1)) return NULL;
     394            6 :           p=ep; goto init;  /* else return match(ms, s, ep); */
     395              :         }
     396         1049 :         default: {
     397         1049 :           if (isdigit(uchar(*(p+1)))) {  /* capture results (%0-%9)? */
     398           24 :             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         1025 :           goto dflt;  /* case default */
     403              :         }
     404              :       }
     405              :     }
     406          536 :     case '\0': {  /* end of pattern */
     407          536 :       return s;  /* match succeeded */
     408              :     }
     409          105 :     case '$': {
     410          105 :       if (*(p+1) == '\0')  /* is the `$' the last char in pattern? */
     411           43 :         return (s == ms->src_end) ? s : NULL;  /* check end of string */
     412           62 :       else goto dflt;
     413              :     }
     414        13873 :     default: dflt: {  /* it is a pattern item */
     415        13873 :       const char *ep = classend(ms, p);  /* points to what is next */
     416        13869 :       int m = s<ms->src_end && singlematch(uchar(*s), p, ep);
     417        13869 :       switch (*ep) {
     418           50 :         case '?': {  /* optional */
     419              :           const char *res;
     420           50 :           if (m && ((res=match(ms, s+1, ep+1)) != NULL))
     421           45 :             return res;
     422            5 :           p=ep+1; goto init;  /* else return match(ms, s, ep+1); */
     423              :         }
     424           28 :         case '*': {  /* 0 or more repetitions */
     425           28 :           return max_expand(ms, s, p, ep);
     426              :         }
     427          835 :         case '+': {  /* 1 or more repetitions */
     428          835 :           return (m ? max_expand(ms, s+1, p, ep) : NULL);
     429              :         }
     430           38 :         case '-': {  /* 0 or more repetitions (minimum) */
     431           38 :           return min_expand(ms, s, p, ep);
     432              :         }
     433        12918 :         default: {
     434        12918 :           if (!m) return NULL;
     435        11056 :           s++; p=ep; goto init;  /* else return match(ms, s+1, ep); */
     436              :         }
     437              :       }
     438              :     }
     439              :   }
     440              : }
     441              : 
     442              : 
     443              : 
     444            9 : static const char *lmemfind (const char *s1, size_t l1,
     445              :                                const char *s2, size_t l2) {
     446            9 :   if (l2 == 0) return s1;  /* empty strings are everywhere */
     447            9 :   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           10 :     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          543 : static void push_onecapture (MatchState *ms, int i, const char *s,
     467              :                                                     const char *e) {
     468          543 :   if (i >= ms->level) {
     469          470 :     if (i == 0)  /* ms->level == 0, too */
     470          469 :       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           73 :     ptrdiff_t l = ms->capture[i].len;
     476           73 :     if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
     477           73 :     if (l == CAP_POSITION)
     478            2 :       lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
     479              :     else
     480           71 :       lua_pushlstring(ms->L, ms->capture[i].init, l);
     481              :   }
     482          542 : }
     483              : 
     484              : 
     485          501 : static int push_captures (MatchState *ms, const char *s, const char *e) {
     486              :   int i;
     487          501 :   int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
     488          501 :   luaL_checkstack(ms->L, nlevels, "too many captures");
     489         1017 :   for (i = 0; i < nlevels; i++)
     490          516 :     push_onecapture(ms, i, s, e);
     491          501 :   return nlevels;  /* number of strings pushed */
     492              : }
     493              : 
     494              : 
     495          560 : static int str_find_aux (lua_State *L, int find) {
     496              :   size_t l1, l2;
     497          560 :   const char *s = luaL_checklstring(L, 1, &l1);
     498          560 :   const char *p = luaL_checklstring(L, 2, &l2);
     499          560 :   ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1;
     500          560 :   if (init < 0) init = 0;
     501          560 :   else if ((size_t)(init) > l1) init = (ptrdiff_t)l1;
     502          560 :   if (find && (lua_toboolean(L, 4) ||  /* explicit request? */
     503           17 :       strpbrk(p, SPECIALS) == NULL)) {  /* or no special characters? */
     504              :     /* do a plain search */
     505            9 :     const char *s2 = lmemfind(s+init, l1-init, p, l2);
     506            9 :     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          551 :     int anchor = (*p == '^') ? (p++, 1) : 0;
     515          551 :     const char *s1=s+init;
     516          551 :     ms.L = L;
     517          551 :     ms.src_init = s;
     518          551 :     ms.src_end = s+l1;
     519              :     do {
     520              :       const char *res;
     521         1861 :       ms.level = 0;
     522         1861 :       if ((res=match(&ms, s1, p)) != NULL) {
     523          486 :         if (find) {
     524            6 :           lua_pushinteger(L, s1-s+1);  /* start */
     525            6 :           lua_pushinteger(L, res-s);   /* end */
     526          486 :           return push_captures(&ms, NULL, 0) + 2;
     527              :         }
     528              :         else
     529          480 :           return push_captures(&ms, s1, res);
     530              :       }
     531         1368 :     } while (s1++ < ms.src_end && !anchor);
     532              :   }
     533           61 :   lua_pushnil(L);  /* not found */
     534           61 :   return 1;
     535              : }
     536              : 
     537              : 
     538           17 : static int str_find (lua_State *L) {
     539           17 :   return str_find_aux(L, 1);
     540              : }
     541              : 
     542              : 
     543          543 : static int str_match (lua_State *L) {
     544          543 :   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           25 :        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           54 : static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
     591              :                                                    const char *e) {
     592              :   size_t l, i;
     593           54 :   const char *news = lua_tolstring(ms->L, 3, &l);
     594          175 :   for (i = 0; i < l; i++) {
     595          122 :     if (news[i] != L_ESC)
     596           79 :       luaL_addchar(b, news[i]);
     597              :     else {
     598           43 :       i++;  /* skip ESC */
     599           43 :       if (!isdigit(uchar(news[i])))
     600            6 :         luaL_addchar(b, news[i]);
     601           37 :       else if (news[i] == '0')
     602           18 :           luaL_addlstring(b, s, e - s);
     603              :       else {
     604           19 :         push_onecapture(ms, news[i] - '1', s, e);
     605           18 :         luaL_addvalue(b);  /* add capture to accumulated result */
     606              :       }
     607              :     }
     608              :   }
     609           53 : }
     610              : 
     611              : 
     612           67 : static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
     613              :                                                        const char *e) {
     614           67 :   lua_State *L = ms->L;
     615           67 :   switch (lua_type(L, 3)) {
     616           54 :     case LUA_TNUMBER:
     617              :     case LUA_TSTRING: {
     618           54 :       add_s(ms, b, s, e);
     619           53 :       return;
     620              :     }
     621            5 :     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            8 :     case LUA_TTABLE: {
     629            8 :       push_onecapture(ms, 0, s, e);
     630            8 :       lua_gettable(L, 3);
     631            8 :       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           33 : static int str_gsub (lua_State *L) {
     645              :   size_t srcl;
     646           33 :   const char *src = luaL_checklstring(L, 1, &srcl);
     647           33 :   const char *p = luaL_checkstring(L, 2);
     648           33 :   int  tr = lua_type(L, 3);
     649           33 :   int max_s = luaL_optint(L, 4, srcl+1);
     650           33 :   int anchor = (*p == '^') ? (p++, 1) : 0;
     651           33 :   int n = 0;
     652              :   MatchState ms;
     653              :   luaL_Buffer b;
     654           33 :   luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
     655              :                    tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
     656              :                       "string/function/table expected");
     657           32 :   luaL_buffinit(L, &b);
     658           32 :   ms.L = L;
     659           32 :   ms.src_init = src;
     660           32 :   ms.src_end = src+srcl;
     661          281 :   while (n < max_s) {
     662              :     const char *e;
     663          278 :     ms.level = 0;
     664          278 :     e = match(&ms, src, p);
     665          277 :     if (e) {
     666           67 :       n++;
     667           67 :       add_value(&ms, &b, src, e);
     668              :     }
     669          275 :     if (e && e>src) /* non empty match? */
     670           65 :       src = e;  /* skip it */
     671          210 :     else if (src < ms.src_end)
     672          187 :       luaL_addchar(&b, *src++);
     673           23 :     else break;
     674          252 :     if (anchor) break;
     675              :   }
     676           29 :   luaL_addlstring(&b, src, ms.src_end-src);
     677           29 :   luaL_pushresult(&b);
     678           29 :   lua_pushinteger(L, n);  /* number of substitutions */
     679           29 :   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            7 : static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
     697              :   size_t l;
     698            7 :   const char *s = luaL_checklstring(L, arg, &l);
     699            5 :   luaL_addchar(b, '"');
     700           90 :   while (l--) {
     701           85 :     switch (*s) {
     702            3 :       case '"': case '\\': case '\n': {
     703            3 :         luaL_addchar(b, '\\');
     704            3 :         luaL_addchar(b, *s);
     705            3 :         break;
     706              :       }
     707            1 :       case '\r': {
     708            1 :         luaL_addlstring(b, "\\r", 2);
     709            1 :         break;
     710              :       }
     711            1 :       case '\0': {
     712            1 :         luaL_addlstring(b, "\\000", 4);
     713            1 :         break;
     714              :       }
     715           80 :       default: {
     716           80 :         luaL_addchar(b, *s);
     717           80 :         break;
     718              :       }
     719              :     }
     720           85 :     s++;
     721              :   }
     722            5 :   luaL_addchar(b, '"');
     723            5 : }
     724              : 
     725           29 : static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
     726           29 :   const char *p = strfrmt;
     727           39 :   while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++;  /* skip flags */
     728           29 :   if ((size_t)(p - strfrmt) >= sizeof(FLAGS))
     729            1 :     luaL_error(L, "invalid format (repeated flags)");
     730           28 :   if (isdigit(uchar(*p))) p++;  /* skip width */
     731           28 :   if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
     732           28 :   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           28 :   if (isdigit(uchar(*p)))
     738            3 :     luaL_error(L, "invalid format (width or precision too long)");
     739           25 :   *(form++) = '%';
     740           25 :   strncpy(form, strfrmt, p - strfrmt + 1);
     741           25 :   form += p - strfrmt + 1;
     742           25 :   *form = '\0';
     743           25 :   return p;
     744              : }
     745              : 
     746              : 
     747            7 : static void addintlen (char *form) {
     748            7 :   size_t l = strlen(form);
     749            7 :   char spec = form[l - 1];
     750            7 :   strcpy(form + l - 1, LUA_INTFRMLEN);
     751            7 :   form[l + sizeof(LUA_INTFRMLEN) - 2] = spec;
     752            7 :   form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0';
     753            7 : }
     754              : 
     755              : 
     756           22 : static int str_format (lua_State *L) {
     757           22 :   int top = lua_gettop(L);
     758           22 :   int arg = 1;
     759              :   size_t sfl;
     760           22 :   const char *strfrmt = luaL_checklstring(L, arg, &sfl);
     761           22 :   const char *strfrmt_end = strfrmt+sfl;
     762              :   luaL_Buffer b;
     763           22 :   luaL_buffinit(L, &b);
     764           68 :   while (strfrmt < strfrmt_end) {
     765           55 :     if (*strfrmt != L_ESC)
     766           23 :       luaL_addchar(&b, *strfrmt++);
     767           32 :     else if (*++strfrmt == L_ESC)
     768            2 :       luaL_addchar(&b, *strfrmt++);  /* %% */
     769              :     else { /* format item */
     770              :       char form[MAX_FORMAT];  /* to store the format (`%...') */
     771              :       char buff[MAX_ITEM];  /* to store the formatted item */
     772           30 :       if (++arg > top)
     773            1 :         luaL_argerror(L, arg, "no value");
     774           29 :       strfrmt = scanformat(L, strfrmt, form);
     775           25 :       switch (*strfrmt++) {
     776            1 :         case 'c': {
     777            1 :           sprintf(buff, form, (int)luaL_checknumber(L, arg));
     778            1 :           break;
     779              :         }
     780            5 :         case 'd':  case 'i': {
     781            5 :           addintlen(form);
     782            5 :           sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg));
     783            4 :           break;
     784              :         }
     785            2 :         case 'o':  case 'u':  case 'x':  case 'X': {
     786            2 :           addintlen(form);
     787            2 :           sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg));
     788            2 :           break;
     789              :         }
     790            1 :         case 'e':  case 'E': case 'f':
     791              :         case 'g': case 'G': {
     792            1 :           sprintf(buff, form, (double)luaL_checknumber(L, arg));
     793            1 :           break;
     794              :         }
     795            7 :         case 'q': {
     796            7 :           addquoted(L, &b, arg);
     797            6 :           continue;  /* skip the 'addsize' at the end */
     798              :         }
     799            8 :         case 's': {
     800              :           size_t l;
     801            8 :           const char *s = luaL_checklstring(L, arg, &l);
     802            8 :           if (!strchr(form, '.') && l >= 100) {
     803              :             /* no precision and string is too long to be formatted;
     804              :                keep original string */
     805            1 :             lua_pushvalue(L, arg);
     806            1 :             luaL_addvalue(&b);
     807            1 :             continue;  /* skip the `addsize' at the end */
     808              :           }
     809              :           else {
     810            7 :             sprintf(buff, form, s);
     811            7 :             break;
     812              :           }
     813              :         }
     814            1 :         default: {  /* also treat cases `pnLlh' */
     815            0 :           return luaL_error(L, "invalid option " LUA_QL("%%%c") " to "
     816            1 :                                LUA_QL("format"), *(strfrmt - 1));
     817              :         }
     818              :       }
     819           15 :       luaL_addlstring(&b, buff, strlen(buff));
     820              :     }
     821              :   }
     822           13 :   luaL_pushresult(&b);
     823           13 :   return 1;
     824              : }
     825              : 
     826              : 
     827              : static const luaL_Reg strlib[] = {
     828              :   {"byte", str_byte},
     829              :   {"char", str_char},
     830              :   {"dump", str_dump},
     831              :   {"find", str_find},
     832              :   {"format", str_format},
     833              :   {"gfind", gfind_nodef},
     834              :   {"gmatch", gmatch},
     835              :   {"gsub", str_gsub},
     836              :   {"len", str_len},
     837              :   {"lower", str_lower},
     838              :   {"match", str_match},
     839              :   {"rep", str_rep},
     840              :   {"reverse", str_reverse},
     841              :   {"sub", str_sub},
     842              :   {"upper", str_upper},
     843              :   {NULL, NULL}
     844              : };
     845              : 
     846              : 
     847           83 : static void createmetatable (lua_State *L) {
     848           83 :   lua_createtable(L, 0, 1);  /* create metatable for strings */
     849           83 :   lua_pushliteral(L, "");  /* dummy string */
     850           83 :   lua_pushvalue(L, -2);
     851           83 :   lua_setmetatable(L, -2);  /* set string metatable */
     852           83 :   lua_pop(L, 1);  /* pop dummy string */
     853           83 :   lua_pushvalue(L, -2);  /* string library... */
     854           83 :   lua_setfield(L, -2, "__index");  /* ...is the __index metamethod */
     855           83 :   lua_pop(L, 1);  /* pop metatable */
     856           83 : }
     857              : 
     858              : 
     859              : /*
     860              : ** Open string library
     861              : */
     862           83 : LUALIB_API int luaopen_string (lua_State *L) {
     863           83 :   luaL_register(L, LUA_STRLIBNAME, strlib);
     864              : #if defined(LUA_COMPAT_GFIND)
     865           83 :   lua_getfield(L, -1, "gmatch");
     866           83 :   lua_setfield(L, -2, "gfind");
     867              : #endif
     868           83 :   createmetatable(L);
     869           83 :   return 1;
     870              : }
     871              : 
        

Generated by: LCOV version 2.0-1