summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2014-01-08 16:34:34 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2014-01-08 16:34:34 -0200
commitcd848cab6bf59314d6b41625bbae918103f654db (patch)
tree08f3585466259b919186766575869d052bdeef6d
parent29256e8960d7f4bae728bb07a86eb0d604f5d98d (diff)
downloadlua-cd848cab6bf59314d6b41625bbae918103f654db.tar.gz
lua-cd848cab6bf59314d6b41625bbae918103f654db.tar.bz2
lua-cd848cab6bf59314d6b41625bbae918103f654db.zip
first implementation for string.pack/unpackfloat + try not to assume
that chars have 8 bits
-rw-r--r--lstrlib.c111
1 files changed, 97 insertions, 14 deletions
diff --git a/lstrlib.c b/lstrlib.c
index 8fd1a433..0be1bf12 100644
--- a/lstrlib.c
+++ b/lstrlib.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstrlib.c,v 1.182 2013/06/20 15:06:51 roberto Exp roberto $ 2** $Id: lstrlib.c,v 1.183 2014/01/05 14:05:58 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*/
@@ -948,6 +948,19 @@ static int str_format (lua_State *L) {
948#define MAXINTSIZE 8 948#define MAXINTSIZE 8
949 949
950 950
951/* number of bits in a character */
952#define NB CHAR_BIT
953
954/* mask for one character (NB ones) */
955#define MC (((lua_Integer)1 << NB) - 1)
956
957/* mask for one character without sign ((NB - 1) ones) */
958#define SM (((lua_Integer)1 << (NB - 1)) - 1)
959
960
961#define SZINT ((int)sizeof(lua_Integer))
962
963
951static union { 964static union {
952 int dummy; 965 int dummy;
953 char little; /* true iff machine is little endian */ 966 char little; /* true iff machine is little endian */
@@ -964,7 +977,7 @@ static int getendian (lua_State *L, int arg) {
964 977
965 978
966static int getintsize (lua_State *L, int arg) { 979static int getintsize (lua_State *L, int arg) {
967 int size = luaL_optint(L, arg, sizeof(lua_Integer)); 980 int size = luaL_optint(L, arg, SZINT);
968 luaL_argcheck(L, 1 <= size && size <= MAXINTSIZE, arg, 981 luaL_argcheck(L, 1 <= size && size <= MAXINTSIZE, arg,
969 "integer size out of valid range"); 982 "integer size out of valid range");
970 return size; 983 return size;
@@ -975,21 +988,21 @@ static int packint (char *buff, lua_Integer n, int littleendian, int size) {
975 int i; 988 int i;
976 if (littleendian) { 989 if (littleendian) {
977 for (i = 0; i < size - 1; i++) { 990 for (i = 0; i < size - 1; i++) {
978 buff[i] = (n & 0xff); 991 buff[i] = (n & MC);
979 n >>= 8; 992 n >>= NB;
980 } 993 }
981 } 994 }
982 else { 995 else {
983 for (i = size - 1; i > 0; i--) { 996 for (i = size - 1; i > 0; i--) {
984 buff[i] = (n & 0xff); 997 buff[i] = (n & MC);
985 n >>= 8; 998 n >>= NB;
986 } 999 }
987 } 1000 }
988 buff[i] = (n & 0xff); /* last byte */ 1001 buff[i] = (n & MC); /* last byte */
989 /* test for overflow: OK if there are only zeros left in higher bytes, 1002 /* test for overflow: OK if there are only zeros left in higher bytes,
990 or if there are only oneś left and packed number is negative (signal 1003 or if there are only oneś left and packed number is negative (signal
991 bit, the higher bit in last byte, is one) */ 1004 bit, the higher bit in last byte, is one) */
992 return ((n & ~(lua_Integer)0xff) == 0 || (n | 0x7f) == ~(lua_Integer)0); 1005 return ((n & ~MC) == 0 || (n | SM) == ~(lua_Integer)0);
993} 1006}
994 1007
995 1008
@@ -1007,17 +1020,17 @@ static int packint_l (lua_State *L) {
1007 1020
1008 1021
1009/* mask to check higher-order byte in a Lua integer */ 1022/* mask to check higher-order byte in a Lua integer */
1010#define HIGHERBYTE (~((lua_Unsigned)~0 >> 8)) 1023#define HIGHERBYTE (MC << (NB * (SZINT - 1)))
1011 1024
1012/* mask to check higher-order byte + signal bit of next byte */ 1025/* mask to check higher-order byte + signal bit of next byte */
1013#define HIGHERBYTE1 (~((lua_Unsigned)~0 >> 9)) 1026#define HIGHERBYTE1 (HIGHERBYTE | (HIGHERBYTE >> 1))
1014 1027
1015static int unpackint (const char *buff, lua_Integer *res, 1028static int unpackint (const char *buff, lua_Integer *res,
1016 int littleendian, int size) { 1029 int littleendian, int size) {
1017 lua_Integer n = 0; 1030 lua_Integer n = 0;
1018 int i; 1031 int i;
1019 for (i = 0; i < size; i++) { 1032 for (i = 0; i < size; i++) {
1020 if (i >= (int)sizeof(lua_Integer)) { /* will throw away a byte? */ 1033 if (i >= SZINT) { /* will throw away a byte? */
1021 /* check for overflow: it is OK to throw away leading zeros for a 1034 /* check for overflow: it is OK to throw away leading zeros for a
1022 positive number; leading ones for a negative number; and one 1035 positive number; leading ones for a negative number; and one
1023 last leading zero to allow unsigned integers with a 1 in 1036 last leading zero to allow unsigned integers with a 1 in
@@ -1027,11 +1040,11 @@ static int unpackint (const char *buff, lua_Integer *res,
1027 ((n & HIGHERBYTE) == 0 && i == size - 1))) /* last zero */ 1040 ((n & HIGHERBYTE) == 0 && i == size - 1))) /* last zero */
1028 return 0; /* overflow */ 1041 return 0; /* overflow */
1029 } 1042 }
1030 n <<= 8; 1043 n <<= NB;
1031 n |= (lua_Integer)(unsigned char)buff[littleendian ? size - 1 - i : i]; 1044 n |= (lua_Integer)(unsigned char)buff[littleendian ? size - 1 - i : i];
1032 } 1045 }
1033 if (size < (int)sizeof(lua_Integer)) { /* need sign extension? */ 1046 if (size < SZINT) { /* need sign extension? */
1034 lua_Integer mask = (~(lua_Integer)0) << (size*8 - 1); 1047 lua_Integer mask = (~(lua_Integer)0) << (size*NB - 1);
1035 if (n & mask) /* negative value? */ 1048 if (n & mask) /* negative value? */
1036 n |= mask; /* signal extension */ 1049 n |= mask; /* signal extension */
1037 } 1050 }
@@ -1056,6 +1069,74 @@ static int unpackint_l (lua_State *L) {
1056 return 1; 1069 return 1;
1057} 1070}
1058 1071
1072
1073static void correctendianess (lua_State *L, char *b, int size, int endianarg) {
1074 int endian = getendian(L, endianarg);
1075 if (endian != nativeendian.little) { /* not native endianess? */
1076 int i = 0;
1077 while (i < --size) {
1078 char temp = b[i];
1079 b[i++] = b[size];
1080 b[size] = temp;
1081 }
1082 }
1083}
1084
1085
1086#define DEFAULTFLOATSIZE \
1087 (sizeof(lua_Number) == sizeof(float) ? "f" : "d")
1088
1089static int getfloatsize (lua_State *L, int arg) {
1090 const char *size = luaL_optstring(L, arg, DEFAULTFLOATSIZE);
1091 luaL_argcheck(L, *size == 'd' || *size == 'f', arg,
1092 "size must be 'f' or 'd'");
1093 return (*size == 'd' ? sizeof(double) : sizeof(float));
1094}
1095
1096
1097static int packfloat_l (lua_State *L) {
1098 float f; double d;
1099 char *pn; /* pointer to number */
1100 lua_Number n = luaL_checknumber(L, 1);
1101 int size = getfloatsize(L, 2);
1102 if (size == sizeof(double)) {
1103 d = (double)n;
1104 pn = (char*)&d;
1105 }
1106 else {
1107 f = (float)n;
1108 pn = (char*)&f;
1109 }
1110 correctendianess(L, pn, size, 3);
1111 lua_pushlstring(L, pn, size);
1112 return 1;
1113}
1114
1115
1116static int unpackfloat_l (lua_State *L) {
1117 lua_Number res;
1118 size_t len;
1119 const char *s = luaL_checklstring(L, 1, &len);
1120 lua_Integer pos = posrelat(luaL_optinteger(L, 2, 1), len);
1121 int size = getfloatsize(L, 3);
1122 luaL_argcheck(L, 1 <= pos && (size_t)pos + size - 1 <= len, 1,
1123 "string too short");
1124 if (size == sizeof(double)) {
1125 double d;
1126 memcpy(&d, s + pos - 1, size);
1127 correctendianess(L, (char*)&d, size, 4);
1128 res = (lua_Number)d;
1129 }
1130 else {
1131 float f;
1132 memcpy(&f, s + pos - 1, size);
1133 correctendianess(L, (char*)&f, size, 4);
1134 res = (lua_Number)f;
1135 }
1136 lua_pushnumber(L, res);
1137 return 1;
1138}
1139
1059/* }====================================================== */ 1140/* }====================================================== */
1060 1141
1061 1142
@@ -1074,7 +1155,9 @@ static const luaL_Reg strlib[] = {
1074 {"reverse", str_reverse}, 1155 {"reverse", str_reverse},
1075 {"sub", str_sub}, 1156 {"sub", str_sub},
1076 {"upper", str_upper}, 1157 {"upper", str_upper},
1158 {"packfloat", packfloat_l},
1077 {"packint", packint_l}, 1159 {"packint", packint_l},
1160 {"unpackfloat", unpackfloat_l},
1078 {"unpackint", unpackint_l}, 1161 {"unpackint", unpackint_l},
1079 {NULL, NULL} 1162 {NULL, NULL}
1080}; 1163};