summaryrefslogtreecommitdiff
path: root/lib/lua/src/LuaLib/lstrlib.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/lua/src/LuaLib/lstrlib.c')
-rw-r--r--lib/lua/src/LuaLib/lstrlib.c420
1 files changed, 259 insertions, 161 deletions
diff --git a/lib/lua/src/LuaLib/lstrlib.c b/lib/lua/src/LuaLib/lstrlib.c
index 2e5f26e..8310752 100644
--- a/lib/lua/src/LuaLib/lstrlib.c
+++ b/lib/lua/src/LuaLib/lstrlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstrlib.c,v 1.4 2004-11-27 21:46:10 pixel Exp $
+** $Id: lstrlib.c,v 1.5 2007-07-27 10:05:55 pixel Exp $
** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
@@ -12,6 +12,7 @@
#include <string.h>
#define lstrlib_c
+#define LUA_LIB
#include "lua.h"
@@ -20,35 +21,31 @@
/* macro to `unsign' a character */
-#ifndef uchar
#define uchar(c) ((unsigned char)(c))
-#endif
-
-typedef long sint32; /* a signed version for size_t */
static int str_len (lua_State *L) {
size_t l;
luaL_checklstring(L, 1, &l);
- lua_pushnumber(L, (lua_Number)l);
+ lua_pushinteger(L, l);
return 1;
}
-static sint32 posrelat (sint32 pos, size_t len) {
+static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) {
/* relative string position: negative means back from end */
- return (pos>=0) ? pos : (sint32)len+pos+1;
+ return (pos>=0) ? pos : (ptrdiff_t)len+pos+1;
}
static int str_sub (lua_State *L) {
size_t l;
const char *s = luaL_checklstring(L, 1, &l);
- sint32 start = posrelat(luaL_checklong(L, 2), l);
- sint32 end = posrelat(luaL_optlong(L, 3, -1), l);
+ ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l);
+ ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l);
if (start < 1) start = 1;
- if (end > (sint32)l) end = (sint32)l;
+ if (end > (ptrdiff_t)l) end = (ptrdiff_t)l;
if (start <= end)
lua_pushlstring(L, s+start-1, end-start+1);
else lua_pushliteral(L, "");
@@ -56,6 +53,17 @@ static int str_sub (lua_State *L) {
}
+static int str_reverse (lua_State *L) {
+ size_t l;
+ 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);
+ return 1;
+}
+
+
static int str_lower (lua_State *L) {
size_t l;
size_t i;
@@ -63,7 +71,7 @@ static int str_lower (lua_State *L) {
const char *s = luaL_checklstring(L, 1, &l);
luaL_buffinit(L, &b);
for (i=0; i<l; i++)
- luaL_putchar(&b, tolower(uchar(s[i])));
+ luaL_addchar(&b, tolower(uchar(s[i])));
luaL_pushresult(&b);
return 1;
}
@@ -76,7 +84,7 @@ static int str_upper (lua_State *L) {
const char *s = luaL_checklstring(L, 1, &l);
luaL_buffinit(L, &b);
for (i=0; i<l; i++)
- luaL_putchar(&b, toupper(uchar(s[i])));
+ luaL_addchar(&b, toupper(uchar(s[i])));
luaL_pushresult(&b);
return 1;
}
@@ -97,11 +105,19 @@ 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);
- sint32 pos = posrelat(luaL_optlong(L, 2, 1), l);
- if (pos <= 0 || (size_t)(pos) > l) /* index out of range? */
- return 0; /* no answer */
- lua_pushnumber(L, uchar(s[pos-1]));
- return 1;
+ ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l);
+ ptrdiff_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 > 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");
+ luaL_checkstack(L, n, "string slice too long");
+ for (i=0; i<n; i++)
+ lua_pushinteger(L, uchar(s[posi+i-1]));
+ return n;
}
@@ -113,7 +129,7 @@ static int str_char (lua_State *L) {
for (i=1; i<=n; i++) {
int c = luaL_checkint(L, i);
luaL_argcheck(L, uchar(c) == c, i, "invalid value");
- luaL_putchar(&b, uchar(c));
+ luaL_addchar(&b, uchar(c));
}
luaL_pushresult(&b);
return 1;
@@ -123,15 +139,16 @@ static int str_char (lua_State *L) {
static int writer (lua_State *L, const void* b, size_t size, void* B) {
(void)L;
luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);
- return 1;
+ return 0;
}
static int str_dump (lua_State *L) {
luaL_Buffer b;
luaL_checktype(L, 1, LUA_TFUNCTION);
+ lua_settop(L, 1);
luaL_buffinit(L,&b);
- if (!lua_dump(L, writer, &b))
+ if (lua_dump(L, writer, &b) != 0)
luaL_error(L, "unable to dump given function");
luaL_pushresult(&b);
return 1;
@@ -145,10 +162,6 @@ static int str_dump (lua_State *L) {
** =======================================================
*/
-#ifndef MAX_CAPTURES
-#define MAX_CAPTURES 32 /* arbitrary limit */
-#endif
-
#define CAP_UNFINISHED (-1)
#define CAP_POSITION (-2)
@@ -160,12 +173,12 @@ typedef struct MatchState {
int level; /* total number of captures (finished or unfinished) */
struct {
const char *init;
- sint32 len;
- } capture[MAX_CAPTURES];
+ ptrdiff_t len;
+ } capture[LUA_MAXCAPTURES];
} MatchState;
-#define ESC '%'
+#define L_ESC '%'
#define SPECIALS "^$*+?.([%-"
@@ -185,19 +198,19 @@ static int capture_to_close (MatchState *ms) {
}
-static const char *luaI_classend (MatchState *ms, const char *p) {
+static const char *classend (MatchState *ms, const char *p) {
switch (*p++) {
- case ESC: {
+ case L_ESC: {
if (*p == '\0')
- luaL_error(ms->L, "malformed pattern (ends with `%')");
+ luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")");
return p+1;
}
case '[': {
if (*p == '^') p++;
do { /* look for a `]' */
if (*p == '\0')
- luaL_error(ms->L, "malformed pattern (missing `]')");
- if (*(p++) == ESC && *p != '\0')
+ luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")");
+ if (*(p++) == L_ESC && *p != '\0')
p++; /* skip escapes (e.g. `%]') */
} while (*p != ']');
return p+1;
@@ -235,9 +248,9 @@ static int matchbracketclass (int c, const char *p, const char *ec) {
p++; /* skip the `^' */
}
while (++p < ec) {
- if (*p == ESC) {
+ if (*p == L_ESC) {
p++;
- if (match_class(c, *p))
+ if (match_class(c, uchar(*p)))
return sig;
}
else if ((*(p+1) == '-') && (p+2 < ec)) {
@@ -251,10 +264,10 @@ static int matchbracketclass (int c, const char *p, const char *ec) {
}
-static int luaI_singlematch (int c, const char *p, const char *ep) {
+static int singlematch (int c, const char *p, const char *ep) {
switch (*p) {
case '.': return 1; /* matches any char */
- case ESC: return match_class(c, *(p+1));
+ case L_ESC: return match_class(c, uchar(*(p+1)));
case '[': return matchbracketclass(c, p, ep-1);
default: return (uchar(*p) == c);
}
@@ -286,8 +299,8 @@ static const char *matchbalance (MatchState *ms, const char *s,
static const char *max_expand (MatchState *ms, const char *s,
const char *p, const char *ep) {
- sint32 i = 0; /* counts maximum expand for item */
- while ((s+i)<ms->src_end && luaI_singlematch(uchar(*(s+i)), p, ep))
+ ptrdiff_t i = 0; /* counts maximum expand for item */
+ while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep))
i++;
/* keeps trying to match with the maximum repetitions */
while (i>=0) {
@@ -305,7 +318,7 @@ static const char *min_expand (MatchState *ms, const char *s,
const char *res = match(ms, s, ep+1);
if (res != NULL)
return res;
- else if (s<ms->src_end && luaI_singlematch(uchar(*s), p, ep))
+ else if (s<ms->src_end && singlematch(uchar(*s), p, ep))
s++; /* try with one more repetition */
else return NULL;
}
@@ -316,7 +329,7 @@ static const char *start_capture (MatchState *ms, const char *s,
const char *p, int what) {
const char *res;
int level = ms->level;
- if (level >= MAX_CAPTURES) luaL_error(ms->L, "too many captures");
+ if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures");
ms->capture[level].init = s;
ms->capture[level].len = what;
ms->level = level+1;
@@ -360,7 +373,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
case ')': { /* end capture */
return end_capture(ms, s, p+1);
}
- case ESC: {
+ case L_ESC: {
switch (*(p+1)) {
case 'b': { /* balanced string? */
s = matchbalance(ms, s, p+2);
@@ -371,8 +384,9 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
const char *ep; char previous;
p += 2;
if (*p != '[')
- luaL_error(ms->L, "missing `[' after `%%f' in pattern");
- ep = luaI_classend(ms, p); /* points to what is next */
+ luaL_error(ms->L, "missing " LUA_QL("[") " after "
+ LUA_QL("%%f") " in pattern");
+ ep = classend(ms, p); /* points to what is next */
previous = (s == ms->src_init) ? '\0' : *(s-1);
if (matchbracketclass(uchar(previous), p, ep-1) ||
!matchbracketclass(uchar(*s), p, ep-1)) return NULL;
@@ -380,7 +394,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
}
default: {
if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */
- s = match_capture(ms, s, *(p+1));
+ s = match_capture(ms, s, uchar(*(p+1)));
if (s == NULL) return NULL;
p+=2; goto init; /* else return match(ms, s, p+2) */
}
@@ -397,8 +411,8 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
else goto dflt;
}
default: dflt: { /* it is a pattern item */
- const char *ep = luaI_classend(ms, p); /* points to what is next */
- int m = s<ms->src_end && luaI_singlematch(uchar(*s), p, ep);
+ const char *ep = classend(ms, p); /* points to what is next */
+ int m = s<ms->src_end && singlematch(uchar(*s), p, ep);
switch (*ep) {
case '?': { /* optional */
const char *res;
@@ -448,45 +462,49 @@ static const char *lmemfind (const char *s1, size_t l1,
}
-static void push_onecapture (MatchState *ms, int i) {
- int l = ms->capture[i].len;
- if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
- if (l == CAP_POSITION)
- lua_pushnumber(ms->L, (lua_Number)(ms->capture[i].init - ms->src_init + 1));
- else
- lua_pushlstring(ms->L, ms->capture[i].init, l);
+static void push_onecapture (MatchState *ms, int i, const char *s,
+ const char *e) {
+ if (i >= ms->level) {
+ if (i == 0) /* ms->level == 0, too */
+ lua_pushlstring(ms->L, s, e - s); /* add whole match */
+ else
+ luaL_error(ms->L, "invalid capture index");
+ }
+ else {
+ ptrdiff_t l = ms->capture[i].len;
+ if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
+ if (l == CAP_POSITION)
+ lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
+ else
+ lua_pushlstring(ms->L, ms->capture[i].init, l);
+ }
}
static int push_captures (MatchState *ms, const char *s, const char *e) {
int i;
- luaL_checkstack(ms->L, ms->level, "too many captures");
- if (ms->level == 0 && s) { /* no explicit captures? */
- lua_pushlstring(ms->L, s, e-s); /* return whole match */
- return 1;
- }
- else { /* return all captures */
- for (i=0; i<ms->level; i++)
- push_onecapture(ms, i);
- return ms->level; /* number of strings pushed */
- }
+ int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
+ luaL_checkstack(ms->L, nlevels, "too many captures");
+ for (i = 0; i < nlevels; i++)
+ push_onecapture(ms, i, s, e);
+ return nlevels; /* number of strings pushed */
}
-static int str_find (lua_State *L) {
+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);
- sint32 init = posrelat(luaL_optlong(L, 3, 1), l1) - 1;
+ ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1;
if (init < 0) init = 0;
- else if ((size_t)(init) > l1) init = (sint32)l1;
- if (lua_toboolean(L, 4) || /* explicit request? */
- strpbrk(p, SPECIALS) == NULL) { /* or no special characters? */
+ 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? */
/* do a plain search */
const char *s2 = lmemfind(s+init, l1-init, p, l2);
if (s2) {
- lua_pushnumber(L, (lua_Number)(s2-s+1));
- lua_pushnumber(L, (lua_Number)(s2-s+l2));
+ lua_pushinteger(L, s2-s+1);
+ lua_pushinteger(L, s2-s+l2);
return 2;
}
}
@@ -501,35 +519,49 @@ static int str_find (lua_State *L) {
const char *res;
ms.level = 0;
if ((res=match(&ms, s1, p)) != NULL) {
- lua_pushnumber(L, (lua_Number)(s1-s+1)); /* start */
- lua_pushnumber(L, (lua_Number)(res-s)); /* end */
- return push_captures(&ms, NULL, 0) + 2;
+ if (find) {
+ lua_pushinteger(L, s1-s+1); /* start */
+ lua_pushinteger(L, res-s); /* end */
+ return push_captures(&ms, NULL, 0) + 2;
+ }
+ else
+ return push_captures(&ms, s1, res);
}
- } while (s1++<ms.src_end && !anchor);
+ } while (s1++ < ms.src_end && !anchor);
}
lua_pushnil(L); /* not found */
return 1;
}
-static int gfind_aux (lua_State *L) {
+static int str_find (lua_State *L) {
+ return str_find_aux(L, 1);
+}
+
+
+static int str_match (lua_State *L) {
+ return str_find_aux(L, 0);
+}
+
+
+static int gmatch_aux (lua_State *L) {
MatchState ms;
- const char *s = lua_tostring(L, lua_upvalueindex(1));
- size_t ls = lua_strlen(L, lua_upvalueindex(1));
+ size_t ls;
+ const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
const char *p = lua_tostring(L, lua_upvalueindex(2));
const char *src;
ms.L = L;
ms.src_init = s;
ms.src_end = s+ls;
- for (src = s + (size_t)lua_tonumber(L, lua_upvalueindex(3));
+ for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3));
src <= ms.src_end;
src++) {
const char *e;
ms.level = 0;
if ((e = match(&ms, src, p)) != NULL) {
- int newstart = e-s;
+ lua_Integer newstart = e-s;
if (e == src) newstart++; /* empty match? go at least one position */
- lua_pushnumber(L, (lua_Number)newstart);
+ lua_pushinteger(L, newstart);
lua_replace(L, lua_upvalueindex(3));
return push_captures(&ms, src, e);
}
@@ -538,48 +570,77 @@ static int gfind_aux (lua_State *L) {
}
-static int gfind (lua_State *L) {
+static int gmatch (lua_State *L) {
luaL_checkstring(L, 1);
luaL_checkstring(L, 2);
lua_settop(L, 2);
- lua_pushnumber(L, 0);
- lua_pushcclosure(L, gfind_aux, 3);
+ lua_pushinteger(L, 0);
+ lua_pushcclosure(L, gmatch_aux, 3);
return 1;
}
-static void add_s (MatchState *ms, luaL_Buffer *b,
- const char *s, const char *e) {
- lua_State *L = ms->L;
- if (lua_isstring(L, 3)) {
- const char *news = lua_tostring(L, 3);
- size_t l = lua_strlen(L, 3);
- size_t i;
- for (i=0; i<l; i++) {
- if (news[i] != ESC)
- luaL_putchar(b, news[i]);
+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;
+ const char *news = lua_tolstring(ms->L, 3, &l);
+ for (i = 0; i < l; i++) {
+ if (news[i] != L_ESC)
+ luaL_addchar(b, news[i]);
+ else {
+ i++; /* skip ESC */
+ if (!isdigit(uchar(news[i])))
+ luaL_addchar(b, news[i]);
+ else if (news[i] == '0')
+ luaL_addlstring(b, s, e - s);
else {
- i++; /* skip ESC */
- if (!isdigit(uchar(news[i])))
- luaL_putchar(b, news[i]);
- else {
- int level = check_capture(ms, news[i]);
- push_onecapture(ms, level);
- luaL_addvalue(b); /* add capture to accumulated result */
- }
+ push_onecapture(ms, news[i] - '1', s, e);
+ luaL_addvalue(b); /* add capture to accumulated result */
}
}
}
- else { /* is a function */
- int n;
- lua_pushvalue(L, 3);
- n = push_captures(ms, s, e);
- lua_call(L, n, 1);
- if (lua_isstring(L, -1))
- luaL_addvalue(b); /* add return to accumulated result */
- else
- lua_pop(L, 1); /* function result is not a string: pop it */
+}
+
+
+static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
+ const char *e) {
+ lua_State *L = ms->L;
+ switch (lua_type(L, 3)) {
+ case LUA_TNUMBER:
+ case LUA_TSTRING: {
+ add_s(ms, b, s, e);
+ return;
+ }
+ case LUA_TFUNCTION: {
+ int n;
+ lua_pushvalue(L, 3);
+ n = push_captures(ms, s, e);
+ lua_call(L, n, 1);
+ break;
+ }
+ case LUA_TTABLE: {
+ push_onecapture(ms, 0, s, e);
+ lua_gettable(L, 3);
+ break;
+ }
+ default: {
+ luaL_argerror(L, 3, "string/function/table expected");
+ 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_addvalue(b); /* add result to accumulator */
}
@@ -592,9 +653,6 @@ static int str_gsub (lua_State *L) {
int n = 0;
MatchState ms;
luaL_Buffer b;
- luaL_argcheck(L,
- lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)),
- 3, "string or function expected");
luaL_buffinit(L, &b);
ms.L = L;
ms.src_init = src;
@@ -605,18 +663,18 @@ static int str_gsub (lua_State *L) {
e = match(&ms, src, p);
if (e) {
n++;
- add_s(&ms, &b, src, e);
+ add_value(&ms, &b, src, e);
}
if (e && e>src) /* non empty match? */
src = e; /* skip it */
else if (src < ms.src_end)
- luaL_putchar(&b, *src++);
+ luaL_addchar(&b, *src++);
else break;
if (anchor) break;
}
luaL_addlstring(&b, src, ms.src_end-src);
luaL_pushresult(&b);
- lua_pushnumber(L, (lua_Number)n); /* number of substitutions */
+ lua_pushinteger(L, n); /* number of substitutions */
return 2;
}
@@ -625,19 +683,28 @@ static int str_gsub (lua_State *L) {
/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
#define MAX_ITEM 512
-/* maximum size of each format specification (such as '%-099.99d') */
-#define MAX_FORMAT 20
+/* valid flags in a format specification */
+#define FLAGS "-+ #0"
+/*
+** maximum size of each format specification (such as '%-099.99d')
+** (+10 accounts for %99.99x plus margin of error)
+*/
+#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10)
-static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) {
+static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
size_t l;
const char *s = luaL_checklstring(L, arg, &l);
- luaL_putchar(b, '"');
+ luaL_addchar(b, '"');
while (l--) {
switch (*s) {
case '"': case '\\': case '\n': {
- luaL_putchar(b, '\\');
- luaL_putchar(b, *s);
+ luaL_addchar(b, '\\');
+ luaL_addchar(b, *s);
+ break;
+ }
+ case '\r': {
+ luaL_addlstring(b, "\\r", 2);
break;
}
case '\0': {
@@ -645,39 +712,46 @@ static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) {
break;
}
default: {
- luaL_putchar(b, *s);
+ luaL_addchar(b, *s);
break;
}
}
s++;
}
- luaL_putchar(b, '"');
+ luaL_addchar(b, '"');
}
-
-static const char *scanformat (lua_State *L, const char *strfrmt,
- char *form, int *hasprecision) {
+static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
const char *p = strfrmt;
- while (strchr("-+ #0", *p)) p++; /* skip flags */
+ while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */
+ if ((size_t)(p - strfrmt) >= sizeof(FLAGS))
+ luaL_error(L, "invalid format (repeated flags)");
if (isdigit(uchar(*p))) p++; /* skip width */
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
if (*p == '.') {
p++;
- *hasprecision = 1;
if (isdigit(uchar(*p))) p++; /* skip precision */
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
}
if (isdigit(uchar(*p)))
luaL_error(L, "invalid format (width or precision too long)");
- if (p-strfrmt+2 > MAX_FORMAT) /* +2 to include `%' and the specifier */
- luaL_error(L, "invalid format (too long)");
- form[0] = '%';
- strncpy(form+1, strfrmt, p-strfrmt+1);
- form[p-strfrmt+2] = 0;
+ *(form++) = '%';
+ strncpy(form, strfrmt, p - strfrmt + 1);
+ form += p - strfrmt + 1;
+ *form = '\0';
return p;
}
+static void addintlen (char *form) {
+ size_t l = strlen(form);
+ 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';
+}
+
+
static int str_format (lua_State *L) {
int arg = 1;
size_t sfl;
@@ -686,40 +760,43 @@ static int str_format (lua_State *L) {
luaL_Buffer b;
luaL_buffinit(L, &b);
while (strfrmt < strfrmt_end) {
- if (*strfrmt != '%')
- luaL_putchar(&b, *strfrmt++);
- else if (*++strfrmt == '%')
- luaL_putchar(&b, *strfrmt++); /* %% */
+ if (*strfrmt != L_ESC)
+ luaL_addchar(&b, *strfrmt++);
+ else if (*++strfrmt == L_ESC)
+ luaL_addchar(&b, *strfrmt++); /* %% */
else { /* format item */
char form[MAX_FORMAT]; /* to store the format (`%...') */
char buff[MAX_ITEM]; /* to store the formatted item */
- int hasprecision = 0;
- if (isdigit(uchar(*strfrmt)) && *(strfrmt+1) == '$')
- return luaL_error(L, "obsolete option (d$) to `format'");
arg++;
- strfrmt = scanformat(L, strfrmt, form, &hasprecision);
+ strfrmt = scanformat(L, strfrmt, form);
switch (*strfrmt++) {
- case 'c': case 'd': case 'i': {
- sprintf(buff, form, luaL_checkint(L, arg));
+ case 'c': {
+ sprintf(buff, form, (int)luaL_checknumber(L, arg));
+ break;
+ }
+ case 'd': case 'i': {
+ addintlen(form);
+ sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg));
break;
}
case 'o': case 'u': case 'x': case 'X': {
- sprintf(buff, form, (unsigned int)(luaL_checknumber(L, arg)));
+ addintlen(form);
+ sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg));
break;
}
case 'e': case 'E': case 'f':
case 'g': case 'G': {
- sprintf(buff, form, luaL_checknumber(L, arg));
+ sprintf(buff, form, (double)luaL_checknumber(L, arg));
break;
}
case 'q': {
- luaI_addquoted(L, &b, arg);
- continue; /* skip the `addsize' at the end */
+ addquoted(L, &b, arg);
+ continue; /* skip the 'addsize' at the end */
}
case 's': {
size_t l;
const char *s = luaL_checklstring(L, arg, &l);
- if (!hasprecision && l >= 100) {
+ if (!strchr(form, '.') && l >= 100) {
/* no precision and string is too long to be formatted;
keep original string */
lua_pushvalue(L, arg);
@@ -732,7 +809,8 @@ static int str_format (lua_State *L) {
}
}
default: { /* also treat cases `pnLlh' */
- return luaL_error(L, "invalid option to `format'");
+ return luaL_error(L, "invalid option " LUA_QL("%%%c") " to "
+ LUA_QL("format"), *(strfrmt - 1));
}
}
luaL_addlstring(&b, buff, strlen(buff));
@@ -743,28 +821,48 @@ static int str_format (lua_State *L) {
}
-static const luaL_reg strlib[] = {
- {"len", str_len},
- {"sub", str_sub},
- {"lower", str_lower},
- {"upper", str_upper},
- {"char", str_char},
- {"rep", str_rep},
+static const luaL_Reg strlib[] = {
{"byte", str_byte},
- {"format", str_format},
+ {"char", str_char},
{"dump", str_dump},
{"find", str_find},
- {"gfind", gfind},
+ {"format", str_format},
+ {"gfind", gfind_nodef},
+ {"gmatch", gmatch},
{"gsub", str_gsub},
+ {"len", str_len},
+ {"lower", str_lower},
+ {"match", str_match},
+ {"rep", str_rep},
+ {"reverse", str_reverse},
+ {"sub", str_sub},
+ {"upper", str_upper},
{NULL, NULL}
};
+static void createmetatable (lua_State *L) {
+ lua_createtable(L, 0, 1); /* create metatable for strings */
+ lua_pushliteral(L, ""); /* dummy string */
+ lua_pushvalue(L, -2);
+ lua_setmetatable(L, -2); /* set string metatable */
+ lua_pop(L, 1); /* pop dummy string */
+ lua_pushvalue(L, -2); /* string library... */
+ lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */
+ lua_pop(L, 1); /* pop metatable */
+}
+
+
/*
** Open string library
*/
LUALIB_API int luaopen_string (lua_State *L) {
- luaL_openlib(L, LUA_STRLIBNAME, strlib, 0);
+ luaL_register(L, LUA_STRLIBNAME, strlib);
+#if defined(LUA_COMPAT_GFIND)
+ lua_getfield(L, -1, "gmatch");
+ lua_setfield(L, -2, "gfind");
+#endif
+ createmetatable(L);
return 1;
}