diff options
| -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 | }; |
