summaryrefslogtreecommitdiff
path: root/lstrlib.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2014-04-16 15:48:31 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2014-04-16 15:48:31 -0300
commit3d4913f7030e3b805de880aa1059d16fc92a8350 (patch)
treed45bb3234cc8079085893feb51198017f2649093 /lstrlib.c
parentc27ef1b79c5063e87efe81ef5915b23e59a47aa4 (diff)
downloadlua-3d4913f7030e3b805de880aa1059d16fc92a8350.tar.gz
lua-3d4913f7030e3b805de880aa1059d16fc92a8350.tar.bz2
lua-3d4913f7030e3b805de880aa1059d16fc92a8350.zip
back to larger sizes for 'dumpint/undumpint' (small Lua should
be able to dump/undump long-long integers)
Diffstat (limited to 'lstrlib.c')
-rw-r--r--lstrlib.c52
1 files changed, 39 insertions, 13 deletions
diff --git a/lstrlib.c b/lstrlib.c
index 6cd07ebd..2b21a132 100644
--- a/lstrlib.c
+++ b/lstrlib.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstrlib.c,v 1.195 2014/04/12 14:45:10 roberto Exp roberto $ 2** $Id: lstrlib.c,v 1.196 2014/04/14 16:59:46 roberto Exp roberto $
3** Standard library for string operations and pattern-matching 3** Standard library for string operations and pattern-matching
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -950,17 +950,17 @@ static int str_format (lua_State *L) {
950/* number of bits in a character */ 950/* number of bits in a character */
951#define NB CHAR_BIT 951#define NB CHAR_BIT
952 952
953/* mask for one character (NB ones) */ 953/* mask for one character (NB 1's) */
954#define MC ((1 << NB) - 1) 954#define MC ((1 << NB) - 1)
955 955
956/* mask for one character without sign ((NB - 1) ones) */ 956/* mask for one character without sign bit ((NB - 1) 1's) */
957#define SM ((1 << (NB - 1)) - 1) 957#define SM (MC >> 1)
958 958
959/* size of a lua_Integer */ 959/* size of a lua_Integer */
960#define SZINT ((int)sizeof(lua_Integer)) 960#define SZINT ((int)sizeof(lua_Integer))
961 961
962/* maximum size for the binary representation of an integer */ 962/* maximum size for the binary representation of an integer */
963#define MAXINTSIZE SZINT 963#define MAXINTSIZE 12
964 964
965 965
966static union { 966static union {
@@ -989,18 +989,24 @@ static int getintsize (lua_State *L, int arg) {
989} 989}
990 990
991 991
992static int dumpint (char *buff, lua_Unsigned n, int littleendian, int size) { 992/* mask for all ones in last byte in a lua Integer */
993#define HIGHERBYTE ((lua_Unsigned)MC << (NB * (SZINT - 1)))
994
995
996static int dumpint (char *buff, lua_Integer m, int littleendian, int size) {
993 int i; 997 int i;
998 lua_Unsigned n = (lua_Unsigned)m;
999 lua_Unsigned mask = (m >= 0) ? 0 : HIGHERBYTE; /* sign extension */
994 if (littleendian) { 1000 if (littleendian) {
995 for (i = 0; i < size - 1; i++) { 1001 for (i = 0; i < size - 1; i++) {
996 buff[i] = (n & MC); 1002 buff[i] = (n & MC);
997 n >>= NB; 1003 n = (n >> NB) | mask;
998 } 1004 }
999 } 1005 }
1000 else { 1006 else {
1001 for (i = size - 1; i > 0; i--) { 1007 for (i = size - 1; i > 0; i--) {
1002 buff[i] = (n & MC); 1008 buff[i] = (n & MC);
1003 n >>= NB; 1009 n = (n >> NB) | mask;
1004 } 1010 }
1005 } 1011 }
1006 buff[i] = (n & MC); /* last byte */ 1012 buff[i] = (n & MC); /* last byte */
@@ -1008,7 +1014,7 @@ static int dumpint (char *buff, lua_Unsigned n, int littleendian, int size) {
1008 /* OK if there are only zeros left in higher bytes, 1014 /* OK if there are only zeros left in higher bytes,
1009 or only ones left (excluding non-signal bits in last byte) */ 1015 or only ones left (excluding non-signal bits in last byte) */
1010 return ((n & ~(lua_Integer)MC) == 0 || 1016 return ((n & ~(lua_Integer)MC) == 0 ||
1011 (n | SM) == (LUA_MAXUNSIGNED >> ((size - 1) * NB))); 1017 (n | SM) == ~(lua_Integer)0);
1012 } 1018 }
1013 else return 1; /* no overflow can occur with full size */ 1019 else return 1; /* no overflow can occur with full size */
1014} 1020}
@@ -1019,7 +1025,7 @@ static int dumpint_l (lua_State *L) {
1019 lua_Integer n = luaL_checkinteger(L, 1); 1025 lua_Integer n = luaL_checkinteger(L, 1);
1020 int size = getintsize(L, 2); 1026 int size = getintsize(L, 2);
1021 int endian = getendian(L, 3); 1027 int endian = getendian(L, 3);
1022 if (dumpint(buff, (lua_Unsigned)n, endian, size)) 1028 if (dumpint(buff, n, endian, size))
1023 lua_pushlstring(L, buff, size); 1029 lua_pushlstring(L, buff, size);
1024 else 1030 else
1025 luaL_error(L, "integer does not fit into given size (%d)", size); 1031 luaL_error(L, "integer does not fit into given size (%d)", size);
@@ -1027,10 +1033,25 @@ static int dumpint_l (lua_State *L) {
1027} 1033}
1028 1034
1029 1035
1030static lua_Integer undumpint (const char *buff, int littleendian, int size) { 1036/* mask to check higher-order byte + signal bit of next (lower) byte */
1037#define HIGHERBYTE1 (HIGHERBYTE | (HIGHERBYTE >> 1))
1038
1039
1040static int undumpint (const char *buff, lua_Integer *res,
1041 int littleendian, int size) {
1031 lua_Integer n = 0; 1042 lua_Integer n = 0;
1032 int i; 1043 int i;
1033 for (i = 0; i < size; i++) { 1044 for (i = 0; i < size; i++) {
1045 if (i >= SZINT) { /* will throw away a byte? */
1046 /* check for overflow: it is OK to throw away leading zeros for a
1047 positive number, leading ones for a negative number, and a
1048 leading zero byte to allow unsigned integers with a 1 in
1049 its "signal bit" */
1050 if (!((n & HIGHERBYTE1) == 0 || /* zeros for positive number */
1051 (n & HIGHERBYTE1) == HIGHERBYTE1 || /* ones for negative number */
1052 (i == size - 1 && (n & HIGHERBYTE) == 0))) /* leading zero */
1053 return 0; /* overflow */
1054 }
1034 n <<= NB; 1055 n <<= NB;
1035 n |= (lua_Integer)(unsigned char)buff[littleendian ? size - 1 - i : i]; 1056 n |= (lua_Integer)(unsigned char)buff[littleendian ? size - 1 - i : i];
1036 } 1057 }
@@ -1038,11 +1059,13 @@ static lua_Integer undumpint (const char *buff, int littleendian, int size) {
1038 lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); 1059 lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1);
1039 n = (lua_Integer)((n ^ mask) - mask); /* do sign extension */ 1060 n = (lua_Integer)((n ^ mask) - mask); /* do sign extension */
1040 } 1061 }
1041 return n; 1062 *res = n;
1063 return 1;
1042} 1064}
1043 1065
1044 1066
1045static int undumpint_l (lua_State *L) { 1067static int undumpint_l (lua_State *L) {
1068 lua_Integer res;
1046 size_t len; 1069 size_t len;
1047 const char *s = luaL_checklstring(L, 1, &len); 1070 const char *s = luaL_checklstring(L, 1, &len);
1048 lua_Integer pos = posrelat(luaL_optinteger(L, 2, 1), len); 1071 lua_Integer pos = posrelat(luaL_optinteger(L, 2, 1), len);
@@ -1050,7 +1073,10 @@ static int undumpint_l (lua_State *L) {
1050 int endian = getendian(L, 4); 1073 int endian = getendian(L, 4);
1051 luaL_argcheck(L, 1 <= pos && (size_t)pos + size - 1 <= len, 1, 1074 luaL_argcheck(L, 1 <= pos && (size_t)pos + size - 1 <= len, 1,
1052 "string too short"); 1075 "string too short");
1053 lua_pushinteger(L, undumpint(s + pos - 1, endian, size)); 1076 if(undumpint(s + pos - 1, &res, endian, size))
1077 lua_pushinteger(L, res);
1078 else
1079 luaL_error(L, "result does not fit into a Lua integer");
1054 return 1; 1080 return 1;
1055} 1081}
1056 1082