diff options
Diffstat (limited to 'lua/lstrlib.c')
-rw-r--r-- | lua/lstrlib.c | 406 |
1 files changed, 253 insertions, 153 deletions
diff --git a/lua/lstrlib.c b/lua/lstrlib.c index 1b4763d..f5d61fd 100644 --- a/lua/lstrlib.c +++ b/lua/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp $ +** $Id: lstrlib.c,v 1.173 2011/11/30 18:24:56 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -20,6 +20,15 @@ #include "lualib.h" +/* +** maximum number of captures that a pattern can do during +** pattern-matching. This limit is arbitrary. +*/ +#if !defined(LUA_MAXCAPTURES) +#define LUA_MAXCAPTURES 32 +#endif + + /* macro to `unsign' a character */ #define uchar(c) ((unsigned char)(c)) @@ -28,39 +37,41 @@ static int str_len (lua_State *L) { size_t l; luaL_checklstring(L, 1, &l); - lua_pushinteger(L, l); + lua_pushinteger(L, (lua_Integer)l); return 1; } -static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { - /* relative string position: negative means back from end */ - if (pos < 0) pos += (ptrdiff_t)len + 1; - return (pos >= 0) ? pos : 0; +/* translate a relative string position: negative means back from end */ +static size_t posrelat (ptrdiff_t pos, size_t len) { + if (pos >= 0) return (size_t)pos; + else if (0u - (size_t)pos > len) return 0; + else return len - ((size_t)-pos) + 1; } static int str_sub (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); - ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); + size_t start = posrelat(luaL_checkinteger(L, 2), l); + size_t end = posrelat(luaL_optinteger(L, 3, -1), l); if (start < 1) start = 1; - if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; + if (end > l) end = l; if (start <= end) - lua_pushlstring(L, s+start-1, end-start+1); + lua_pushlstring(L, s + start - 1, end - start + 1); else lua_pushliteral(L, ""); return 1; } static int str_reverse (lua_State *L) { - size_t l; + size_t l, i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); - luaL_buffinit(L, &b); - while (l--) luaL_addchar(&b, s[l]); - luaL_pushresult(&b); + char *p = luaL_buffinitsize(L, &b, l); + for (i = 0; i < l; i++) + p[i] = s[l - i - 1]; + luaL_pushresultsize(&b, l); return 1; } @@ -70,10 +81,10 @@ static int str_lower (lua_State *L) { size_t i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); - luaL_buffinit(L, &b); + char *p = luaL_buffinitsize(L, &b, l); for (i=0; i<l; i++) - luaL_addchar(&b, tolower(uchar(s[i]))); - luaL_pushresult(&b); + p[i] = tolower(uchar(s[i])); + luaL_pushresultsize(&b, l); return 1; } @@ -83,22 +94,36 @@ static int str_upper (lua_State *L) { size_t i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); - luaL_buffinit(L, &b); + char *p = luaL_buffinitsize(L, &b, l); for (i=0; i<l; i++) - luaL_addchar(&b, toupper(uchar(s[i]))); - luaL_pushresult(&b); + p[i] = toupper(uchar(s[i])); + luaL_pushresultsize(&b, l); return 1; } + +/* reasonable limit to avoid arithmetic overflow */ +#define MAXSIZE ((~(size_t)0) >> 1) + static int str_rep (lua_State *L) { - size_t l; - luaL_Buffer b; + size_t l, lsep; const char *s = luaL_checklstring(L, 1, &l); int n = luaL_checkint(L, 2); - luaL_buffinit(L, &b); - while (n-- > 0) - luaL_addlstring(&b, s, l); - luaL_pushresult(&b); + const char *sep = luaL_optlstring(L, 3, "", &lsep); + if (n <= 0) lua_pushliteral(L, ""); + else if (l + lsep < l || l + lsep >= MAXSIZE / n) /* may overflow? */ + return luaL_error(L, "resulting string too large"); + else { + size_t totallen = n * l + (n - 1) * lsep; + luaL_Buffer b; + char *p = luaL_buffinitsize(L, &b, totallen); + while (n-- > 1) { /* first n-1 copies (followed by separator) */ + memcpy(p, s, l * sizeof(char)); p += l; + memcpy(p, sep, lsep * sizeof(char)); p += lsep; + } + memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ + luaL_pushresultsize(&b, totallen); + } return 1; } @@ -106,15 +131,15 @@ static int str_rep (lua_State *L) { static int str_byte (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); - ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); + size_t posi = posrelat(luaL_optinteger(L, 2, 1), l); + size_t pose = posrelat(luaL_optinteger(L, 3, posi), l); int n, i; - if (posi <= 0) posi = 1; - if ((size_t)pose > l) pose = l; + if (posi < 1) posi = 1; + if (pose > l) pose = l; if (posi > pose) return 0; /* empty interval; return no values */ n = (int)(pose - posi + 1); - if (posi + n <= pose) /* overflow? */ - luaL_error(L, "string slice too long"); + if (posi + n <= pose) /* (size_t -> int) overflow? */ + return luaL_error(L, "string slice too long"); luaL_checkstack(L, n, "string slice too long"); for (i=0; i<n; i++) lua_pushinteger(L, uchar(s[posi+i-1])); @@ -126,13 +151,13 @@ static int str_char (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int i; luaL_Buffer b; - luaL_buffinit(L, &b); + char *p = luaL_buffinitsize(L, &b, n); for (i=1; i<=n; i++) { int c = luaL_checkint(L, i); - luaL_argcheck(L, uchar(c) == c, i, "invalid value"); - luaL_addchar(&b, uchar(c)); + luaL_argcheck(L, uchar(c) == c, i, "value out of range"); + p[i - 1] = uchar(c); } - luaL_pushresult(&b); + luaL_pushresultsize(&b, n); return 1; } @@ -150,7 +175,7 @@ static int str_dump (lua_State *L) { lua_settop(L, 1); luaL_buffinit(L,&b); if (lua_dump(L, writer, &b) != 0) - luaL_error(L, "unable to dump given function"); + return luaL_error(L, "unable to dump given function"); luaL_pushresult(&b); return 1; } @@ -169,7 +194,8 @@ static int str_dump (lua_State *L) { typedef struct MatchState { const char *src_init; /* init of source string */ - const char *src_end; /* end (`\0') of source string */ + const char *src_end; /* end ('\0') of source string */ + const char *p_end; /* end ('\0') of pattern */ lua_State *L; int level; /* total number of captures (finished or unfinished) */ struct { @@ -186,7 +212,7 @@ typedef struct MatchState { static int check_capture (MatchState *ms, int l) { l -= '1'; if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) - return luaL_error(ms->L, "invalid capture index"); + return luaL_error(ms->L, "invalid capture index %%%d", l + 1); return l; } @@ -202,16 +228,16 @@ static int capture_to_close (MatchState *ms) { static const char *classend (MatchState *ms, const char *p) { switch (*p++) { case L_ESC: { - if (*p == '\0') + if (p == ms->p_end) luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); return p+1; } case '[': { if (*p == '^') p++; do { /* look for a `]' */ - if (*p == '\0') + if (p == ms->p_end) luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); - if (*(p++) == L_ESC && *p != '\0') + if (*(p++) == L_ESC && p < ms->p_end) p++; /* skip escapes (e.g. `%]') */ } while (*p != ']'); return p+1; @@ -229,13 +255,14 @@ static int match_class (int c, int cl) { case 'a' : res = isalpha(c); break; case 'c' : res = iscntrl(c); break; case 'd' : res = isdigit(c); break; + case 'g' : res = isgraph(c); break; case 'l' : res = islower(c); break; case 'p' : res = ispunct(c); break; case 's' : res = isspace(c); break; case 'u' : res = isupper(c); break; case 'w' : res = isalnum(c); break; case 'x' : res = isxdigit(c); break; - case 'z' : res = (c == 0); break; + case 'z' : res = (c == 0); break; /* deprecated option */ default: return (cl == c); } return (islower(cl) ? res : !res); @@ -280,8 +307,9 @@ static const char *match (MatchState *ms, const char *s, const char *p); static const char *matchbalance (MatchState *ms, const char *s, const char *p) { - if (*p == 0 || *(p+1) == 0) - luaL_error(ms->L, "unbalanced pattern"); + if (p >= ms->p_end - 1) + luaL_error(ms->L, "malformed pattern " + "(missing arguments to " LUA_QL("%%b") ")"); if (*s != *p) return NULL; else { int b = *p; @@ -364,6 +392,8 @@ static const char *match_capture (MatchState *ms, const char *s, int l) { static const char *match (MatchState *ms, const char *s, const char *p) { init: /* using goto's to optimize tail recursion */ + if (p == ms->p_end) /* end of pattern? */ + return s; /* match succeeded */ switch (*p) { case '(': { /* start capture */ if (*(p+1) == ')') /* position capture? */ @@ -374,7 +404,12 @@ static const char *match (MatchState *ms, const char *s, const char *p) { case ')': { /* end capture */ return end_capture(ms, s, p+1); } - case L_ESC: { + case '$': { + if ((p+1) == ms->p_end) /* is the `$' the last char in pattern? */ + return (s == ms->src_end) ? s : NULL; /* check end of string */ + else goto dflt; + } + case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ switch (*(p+1)) { case 'b': { /* balanced string? */ s = matchbalance(ms, s, p+2); @@ -393,27 +428,19 @@ static const char *match (MatchState *ms, const char *s, const char *p) { !matchbracketclass(uchar(*s), p, ep-1)) return NULL; p=ep; goto init; /* else return match(ms, s, ep); */ } - default: { - if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ - s = match_capture(ms, s, uchar(*(p+1))); - if (s == NULL) return NULL; - p+=2; goto init; /* else return match(ms, s, p+2) */ - } - goto dflt; /* case default */ + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': { /* capture results (%0-%9)? */ + s = match_capture(ms, s, uchar(*(p+1))); + if (s == NULL) return NULL; + p+=2; goto init; /* else return match(ms, s, p+2) */ } + default: goto dflt; } } - case '\0': { /* end of pattern */ - return s; /* match succeeded */ - } - case '$': { - if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ - return (s == ms->src_end) ? s : NULL; /* check end of string */ - else goto dflt; - } - default: dflt: { /* it is a pattern item */ + default: dflt: { /* pattern class plus optional suffix */ const char *ep = classend(ms, p); /* points to what is next */ - int m = s<ms->src_end && singlematch(uchar(*s), p, ep); + int m = s < ms->src_end && singlematch(uchar(*s), p, ep); switch (*ep) { case '?': { /* optional */ const char *res; @@ -492,37 +519,56 @@ static int push_captures (MatchState *ms, const char *s, const char *e) { } +/* check whether pattern has no special characters */ +static int nospecials (const char *p, size_t l) { + size_t upto = 0; + do { + if (strpbrk(p + upto, SPECIALS)) + return 0; /* pattern has a special character */ + upto += strlen(p + upto) + 1; /* may have more after \0 */ + } while (upto <= l); + return 1; /* no special chars found */ +} + + static int str_find_aux (lua_State *L, int find) { - size_t l1, l2; - const char *s = luaL_checklstring(L, 1, &l1); - const char *p = luaL_checklstring(L, 2, &l2); - ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; - if (init < 0) init = 0; - else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; - if (find && (lua_toboolean(L, 4) || /* explicit request? */ - strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ + size_t ls, lp; + const char *s = luaL_checklstring(L, 1, &ls); + const char *p = luaL_checklstring(L, 2, &lp); + size_t init = posrelat(luaL_optinteger(L, 3, 1), ls); + if (init < 1) init = 1; + else if (init > ls + 1) { /* start after string's end? */ + lua_pushnil(L); /* cannot find anything */ + return 1; + } + /* explicit request or no special characters? */ + if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { /* do a plain search */ - const char *s2 = lmemfind(s+init, l1-init, p, l2); + const char *s2 = lmemfind(s + init - 1, ls - init + 1, p, lp); if (s2) { - lua_pushinteger(L, s2-s+1); - lua_pushinteger(L, s2-s+l2); + lua_pushinteger(L, s2 - s + 1); + lua_pushinteger(L, s2 - s + lp); return 2; } } else { MatchState ms; - int anchor = (*p == '^') ? (p++, 1) : 0; - const char *s1=s+init; + const char *s1 = s + init - 1; + int anchor = (*p == '^'); + if (anchor) { + p++; lp--; /* skip anchor character */ + } ms.L = L; ms.src_init = s; - ms.src_end = s+l1; + ms.src_end = s + ls; + ms.p_end = p + lp; do { const char *res; ms.level = 0; if ((res=match(&ms, s1, p)) != NULL) { if (find) { - lua_pushinteger(L, s1-s+1); /* start */ - lua_pushinteger(L, res-s); /* end */ + lua_pushinteger(L, s1 - s + 1); /* start */ + lua_pushinteger(L, res - s); /* end */ return push_captures(&ms, NULL, 0) + 2; } else @@ -547,13 +593,14 @@ static int str_match (lua_State *L) { static int gmatch_aux (lua_State *L) { MatchState ms; - size_t ls; + size_t ls, lp; const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); - const char *p = lua_tostring(L, lua_upvalueindex(2)); + const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp); const char *src; ms.L = L; ms.src_init = s; ms.src_end = s+ls; + ms.p_end = p + lp; for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); src <= ms.src_end; src++) { @@ -581,12 +628,6 @@ static int gmatch (lua_State *L) { } -static int gfind_nodef (lua_State *L) { - return luaL_error(L, LUA_QL("string.gfind") " was renamed to " - LUA_QL("string.gmatch")); -} - - static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, const char *e) { size_t l, i; @@ -596,8 +637,12 @@ static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, luaL_addchar(b, news[i]); else { i++; /* skip ESC */ - if (!isdigit(uchar(news[i]))) + if (!isdigit(uchar(news[i]))) { + if (news[i] != L_ESC) + luaL_error(ms->L, "invalid use of " LUA_QL("%c") + " in replacement string", L_ESC); luaL_addchar(b, news[i]); + } else if (news[i] == '0') luaL_addlstring(b, s, e - s); else { @@ -610,14 +655,9 @@ static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, - const char *e) { + const char *e, int tr) { lua_State *L = ms->L; - switch (lua_type(L, 3)) { - case LUA_TNUMBER: - case LUA_TSTRING: { - add_s(ms, b, s, e); - return; - } + switch (tr) { case LUA_TFUNCTION: { int n; lua_pushvalue(L, 3); @@ -630,41 +670,49 @@ static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, lua_gettable(L, 3); break; } + default: { /* LUA_TNUMBER or LUA_TSTRING */ + add_s(ms, b, s, e); + return; + } } if (!lua_toboolean(L, -1)) { /* nil or false? */ lua_pop(L, 1); lua_pushlstring(L, s, e - s); /* keep original text */ } else if (!lua_isstring(L, -1)) - luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); + luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); luaL_addvalue(b); /* add result to accumulator */ } static int str_gsub (lua_State *L) { - size_t srcl; + size_t srcl, lp; const char *src = luaL_checklstring(L, 1, &srcl); - const char *p = luaL_checkstring(L, 2); - int tr = lua_type(L, 3); - int max_s = luaL_optint(L, 4, srcl+1); - int anchor = (*p == '^') ? (p++, 1) : 0; - int n = 0; + const char *p = luaL_checklstring(L, 2, &lp); + int tr = lua_type(L, 3); + size_t max_s = luaL_optinteger(L, 4, srcl+1); + int anchor = (*p == '^'); + size_t n = 0; MatchState ms; luaL_Buffer b; luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, "string/function/table expected"); luaL_buffinit(L, &b); + if (anchor) { + p++; lp--; /* skip anchor character */ + } ms.L = L; ms.src_init = src; ms.src_end = src+srcl; + ms.p_end = p + lp; while (n < max_s) { const char *e; ms.level = 0; e = match(&ms, src, p); if (e) { n++; - add_value(&ms, &b, src, e); + add_value(&ms, &b, src, e, tr); } if (e && e>src) /* non empty match? */ src = e; /* skip it */ @@ -682,6 +730,49 @@ static int str_gsub (lua_State *L) { /* }====================================================== */ + +/* +** {====================================================== +** STRING FORMAT +** ======================================================= +*/ + +/* +** LUA_INTFRMLEN is the length modifier for integer conversions in +** 'string.format'; LUA_INTFRM_T is the integer type corresponding to +** the previous length +*/ +#if !defined(LUA_INTFRMLEN) /* { */ +#if defined(LUA_USE_LONGLONG) + +#define LUA_INTFRMLEN "ll" +#define LUA_INTFRM_T long long + +#else + +#define LUA_INTFRMLEN "l" +#define LUA_INTFRM_T long + +#endif +#endif /* } */ + +#define MAX_UINTFRM ((lua_Number)(~(unsigned LUA_INTFRM_T)0)) +#define MAX_INTFRM ((lua_Number)((~(unsigned LUA_INTFRM_T)0)/2)) +#define MIN_INTFRM (-(lua_Number)((~(unsigned LUA_INTFRM_T)0)/2) - 1) + +/* +** LUA_FLTFRMLEN is the length modifier for float conversions in +** 'string.format'; LUA_FLTFRM_T is the float type corresponding to +** the previous length +*/ +#if !defined(LUA_FLTFRMLEN) + +#define LUA_FLTFRMLEN "" +#define LUA_FLTFRM_T double + +#endif + + /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ #define MAX_ITEM 512 /* valid flags in a format specification */ @@ -698,25 +789,20 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { const char *s = luaL_checklstring(L, arg, &l); luaL_addchar(b, '"'); while (l--) { - switch (*s) { - case '"': case '\\': case '\n': { - luaL_addchar(b, '\\'); - luaL_addchar(b, *s); - break; - } - case '\r': { - luaL_addlstring(b, "\\r", 2); - break; - } - case '\0': { - luaL_addlstring(b, "\\000", 4); - break; - } - default: { - luaL_addchar(b, *s); - break; - } + if (*s == '"' || *s == '\\' || *s == '\n') { + luaL_addchar(b, '\\'); + luaL_addchar(b, *s); } + else if (*s == '\0' || iscntrl(uchar(*s))) { + char buff[10]; + if (!isdigit(uchar(*(s+1)))) + sprintf(buff, "\\%d", (int)uchar(*s)); + else + sprintf(buff, "\\%03d", (int)uchar(*s)); + luaL_addstring(b, buff); + } + else + luaL_addchar(b, *s); s++; } luaL_addchar(b, '"'); @@ -725,7 +811,7 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { const char *p = strfrmt; while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ - if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) + if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char)) luaL_error(L, "invalid format (repeated flags)"); if (isdigit(uchar(*p))) p++; /* skip width */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ @@ -737,23 +823,28 @@ static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { if (isdigit(uchar(*p))) luaL_error(L, "invalid format (width or precision too long)"); *(form++) = '%'; - strncpy(form, strfrmt, p - strfrmt + 1); + memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char)); form += p - strfrmt + 1; *form = '\0'; return p; } -static void addintlen (char *form) { +/* +** add length modifier into formats +*/ +static void addlenmod (char *form, const char *lenmod) { size_t l = strlen(form); + size_t lm = strlen(lenmod); char spec = form[l - 1]; - strcpy(form + l - 1, LUA_INTFRMLEN); - form[l + sizeof(LUA_INTFRMLEN) - 2] = spec; - form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0'; + strcpy(form + l - 1, lenmod); + form[l + lm - 1] = spec; + form[l + lm] = '\0'; } static int str_format (lua_State *L) { + int top = lua_gettop(L); int arg = 1; size_t sfl; const char *strfrmt = luaL_checklstring(L, arg, &sfl); @@ -767,45 +858,57 @@ static int str_format (lua_State *L) { luaL_addchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format (`%...') */ - char buff[MAX_ITEM]; /* to store the formatted item */ - arg++; + char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ + int nb = 0; /* number of bytes in added item */ + if (++arg > top) + luaL_argerror(L, arg, "no value"); strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { - sprintf(buff, form, (int)luaL_checknumber(L, arg)); + nb = sprintf(buff, form, luaL_checkint(L, arg)); break; } case 'd': case 'i': { - addintlen(form); - sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); + lua_Number n = luaL_checknumber(L, arg); + luaL_argcheck(L, (MIN_INTFRM - 1) < n && n < (MAX_INTFRM + 1), arg, + "not a number in proper range"); + addlenmod(form, LUA_INTFRMLEN); + nb = sprintf(buff, form, (LUA_INTFRM_T)n); break; } case 'o': case 'u': case 'x': case 'X': { - addintlen(form); - sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); + lua_Number n = luaL_checknumber(L, arg); + luaL_argcheck(L, 0 <= n && n < (MAX_UINTFRM + 1), arg, + "not a non-negative number in proper range"); + addlenmod(form, LUA_INTFRMLEN); + nb = sprintf(buff, form, (unsigned LUA_INTFRM_T)n); break; } case 'e': case 'E': case 'f': +#if defined(LUA_USE_AFORMAT) + case 'a': case 'A': +#endif case 'g': case 'G': { - sprintf(buff, form, (double)luaL_checknumber(L, arg)); + addlenmod(form, LUA_FLTFRMLEN); + nb = sprintf(buff, form, (LUA_FLTFRM_T)luaL_checknumber(L, arg)); break; } case 'q': { addquoted(L, &b, arg); - continue; /* skip the 'addsize' at the end */ + break; } case 's': { size_t l; - const char *s = luaL_checklstring(L, arg, &l); + const char *s = luaL_tolstring(L, arg, &l); if (!strchr(form, '.') && l >= 100) { /* no precision and string is too long to be formatted; keep original string */ - lua_pushvalue(L, arg); luaL_addvalue(&b); - continue; /* skip the `addsize' at the end */ + break; } else { - sprintf(buff, form, s); + nb = sprintf(buff, form, s); + lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ break; } } @@ -814,13 +917,15 @@ static int str_format (lua_State *L) { LUA_QL("format"), *(strfrmt - 1)); } } - luaL_addlstring(&b, buff, strlen(buff)); + luaL_addsize(&b, nb); } } luaL_pushresult(&b); return 1; } +/* }====================================================== */ + static const luaL_Reg strlib[] = { {"byte", str_byte}, @@ -828,7 +933,6 @@ static const luaL_Reg strlib[] = { {"dump", str_dump}, {"find", str_find}, {"format", str_format}, - {"gfind", gfind_nodef}, {"gmatch", gmatch}, {"gsub", str_gsub}, {"len", str_len}, @@ -843,13 +947,13 @@ static const luaL_Reg strlib[] = { static void createmetatable (lua_State *L) { - lua_createtable(L, 0, 1); /* create metatable for strings */ + lua_createtable(L, 0, 1); /* table to be metatable for strings */ lua_pushliteral(L, ""); /* dummy string */ - lua_pushvalue(L, -2); - lua_setmetatable(L, -2); /* set string metatable */ + lua_pushvalue(L, -2); /* copy table */ + lua_setmetatable(L, -2); /* set table as metatable for strings */ lua_pop(L, 1); /* pop dummy string */ - lua_pushvalue(L, -2); /* string library... */ - lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */ + lua_pushvalue(L, -2); /* get string library */ + lua_setfield(L, -2, "__index"); /* metatable.__index = string */ lua_pop(L, 1); /* pop metatable */ } @@ -857,12 +961,8 @@ static void createmetatable (lua_State *L) { /* ** Open string library */ -LUALIB_API int luaopen_string (lua_State *L) { - luaL_register(L, LUA_STRLIBNAME, strlib); -#if defined(LUA_COMPAT_GFIND) - lua_getfield(L, -1, "gmatch"); - lua_setfield(L, -2, "gfind"); -#endif +LUAMOD_API int luaopen_string (lua_State *L) { + luaL_newlib(L, strlib); createmetatable(L); return 1; } |