diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-01-08 16:34:34 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-01-08 16:34:34 -0200 |
commit | cd848cab6bf59314d6b41625bbae918103f654db (patch) | |
tree | 08f3585466259b919186766575869d052bdeef6d | |
parent | 29256e8960d7f4bae728bb07a86eb0d604f5d98d (diff) | |
download | lua-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.c | 111 |
1 files changed, 97 insertions, 14 deletions
@@ -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 | |||
951 | static union { | 964 | static 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 | ||
966 | static int getintsize (lua_State *L, int arg) { | 979 | static 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 | ||
1015 | static int unpackint (const char *buff, lua_Integer *res, | 1028 | static 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 | |||
1073 | static 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 | |||
1089 | static 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 | |||
1097 | static 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 | |||
1116 | static 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 | }; |