diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-10-20 14:44:54 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-10-20 14:44:54 -0200 |
commit | 57559547a30164e60ffa05422f9db990517dbcc5 (patch) | |
tree | 9abc4290cd0ad3e223be0f85b8717a0081ee6d55 /lstrlib.c | |
parent | cfa84e123272acff178fe2e4cf5af7ec20e56572 (diff) | |
download | lua-57559547a30164e60ffa05422f9db990517dbcc5.tar.gz lua-57559547a30164e60ffa05422f9db990517dbcc5.tar.bz2 lua-57559547a30164e60ffa05422f9db990517dbcc5.zip |
in 'pack'/'unpack', endianness and alignment treated like options +
small changes in names and handling of internal options ('KOption')
Diffstat (limited to 'lstrlib.c')
-rw-r--r-- | lstrlib.c | 107 |
1 files changed, 52 insertions, 55 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstrlib.c,v 1.203 2014/10/17 10:55:28 roberto Exp roberto $ | 2 | ** $Id: lstrlib.c,v 1.204 2014/10/17 16:28:21 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 | */ |
@@ -1000,8 +1000,21 @@ typedef struct Header { | |||
1000 | } Header; | 1000 | } Header; |
1001 | 1001 | ||
1002 | 1002 | ||
1003 | typedef enum KOption {Kint, Kuint, Kfloat, Kchar, Kstring, Kstring0, | 1003 | /* |
1004 | Kspace, Kpadding, Kpaddalig} KOption; | 1004 | ** options for pack/unpack |
1005 | */ | ||
1006 | typedef enum KOption { | ||
1007 | Kint, /* signed integers */ | ||
1008 | Kuint, /* unsigned integers */ | ||
1009 | Kfloat, /* floating-point numbers */ | ||
1010 | Kchar, /* fixed-length strings */ | ||
1011 | Kstring, /* strings with prefixed length */ | ||
1012 | Kzstr, /* zero-terminated strings */ | ||
1013 | Kpadding, /* padding */ | ||
1014 | Kpaddalign, /* padding for alignment */ | ||
1015 | Knop, /* no-op (configuration or spaces) */ | ||
1016 | Keof /* end of format */ | ||
1017 | } KOption; | ||
1005 | 1018 | ||
1006 | 1019 | ||
1007 | /* | 1020 | /* |
@@ -1036,37 +1049,12 @@ static int getnumlimit (Header *h, const char **fmt, int df) { | |||
1036 | 1049 | ||
1037 | 1050 | ||
1038 | /* | 1051 | /* |
1039 | ** Reads an option endianness indication ('<'/'>') and | 1052 | ** Initialize Header |
1040 | ** returns true if operation should use little endian. | ||
1041 | */ | ||
1042 | static int getendian (const char **fmt) { | ||
1043 | if (**fmt == '<' || **fmt == '>') /* explicit endianness? */ | ||
1044 | return (*((*fmt)++) == '<'); /* true iff little endian */ | ||
1045 | else /* no endian indication */ | ||
1046 | return nativeendian.little; /* use native */ | ||
1047 | } | ||
1048 | |||
1049 | |||
1050 | /* | ||
1051 | ** Read and return maximum alignment to be used | ||
1052 | */ | ||
1053 | static int getalignment (Header *h, const char **fmt) { | ||
1054 | if (**fmt == '!') { /* explicit alignment? */ | ||
1055 | (*fmt)++; /* skip '!' */ | ||
1056 | return getnumlimit(h, fmt, MAXALIGN); | ||
1057 | } | ||
1058 | else | ||
1059 | return 1; /* default is no alignment */ | ||
1060 | } | ||
1061 | |||
1062 | |||
1063 | /* | ||
1064 | ** Read optional endianness and alignment indications | ||
1065 | */ | 1053 | */ |
1066 | static void getheader (lua_State *L, Header *h, const char **fmt) { | 1054 | static void initheader (lua_State *L, Header *h) { |
1067 | h->L = L; | 1055 | h->L = L; |
1068 | h->islittle = getendian(fmt); | 1056 | h->islittle = nativeendian.little; |
1069 | h->maxalign = getalignment(h, fmt); | 1057 | h->maxalign = 1; |
1070 | } | 1058 | } |
1071 | 1059 | ||
1072 | 1060 | ||
@@ -1075,6 +1063,7 @@ static void getheader (lua_State *L, Header *h, const char **fmt) { | |||
1075 | */ | 1063 | */ |
1076 | static KOption getoption (Header *h, const char **fmt, int *size) { | 1064 | static KOption getoption (Header *h, const char **fmt, int *size) { |
1077 | int opt = *((*fmt)++); | 1065 | int opt = *((*fmt)++); |
1066 | *size = 0; /* default */ | ||
1078 | switch (opt) { | 1067 | switch (opt) { |
1079 | case 'b': *size = sizeof(char); return Kint; | 1068 | case 'b': *size = sizeof(char); return Kint; |
1080 | case 'B': *size = sizeof(char); return Kuint; | 1069 | case 'B': *size = sizeof(char); return Kuint; |
@@ -1092,14 +1081,17 @@ static KOption getoption (Header *h, const char **fmt, int *size) { | |||
1092 | case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; | 1081 | case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; |
1093 | case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; | 1082 | case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; |
1094 | case 'c': *size = getnum(fmt, 1); return Kchar; | 1083 | case 'c': *size = getnum(fmt, 1); return Kchar; |
1095 | case 'z': *size = 0; return Kstring0; | 1084 | case 'z': return Kzstr; |
1096 | case 'x': *size = 1; return Kpadding; | 1085 | case 'x': *size = 1; return Kpadding; |
1097 | case 'X': *size = 0; return Kpaddalig; | 1086 | case 'X': return Kpaddalign; |
1098 | case ' ': *size = 0; return Kspace; | 1087 | case ' ': return Knop; |
1088 | case '\0': return Keof; | ||
1089 | case '<': h->islittle = 1; return Knop; | ||
1090 | case '>': h->islittle = 0; return Knop; | ||
1091 | case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); return Knop; | ||
1099 | default: { | 1092 | default: { |
1100 | *size = 0; /* to avoid warnings */ | ||
1101 | luaL_error(h->L, "invalid format option '%c'", opt); | 1093 | luaL_error(h->L, "invalid format option '%c'", opt); |
1102 | return (KOption)0; | 1094 | return Knop; |
1103 | } | 1095 | } |
1104 | } | 1096 | } |
1105 | } | 1097 | } |
@@ -1116,17 +1108,20 @@ static KOption getoption (Header *h, const char **fmt, int *size) { | |||
1116 | */ | 1108 | */ |
1117 | static KOption getdetails (Header *h, size_t totalsize, | 1109 | static KOption getdetails (Header *h, size_t totalsize, |
1118 | const char **fmt, int *psize, int *ntoalign) { | 1110 | const char **fmt, int *psize, int *ntoalign) { |
1119 | KOption opt = getoption(h, fmt, psize); | 1111 | int align; |
1120 | int align = *psize; /* usually, alignment follows size */ | 1112 | KOption opt; |
1121 | if (opt == Kpaddalig) { | 1113 | do { |
1122 | if (**fmt == '\0' || strchr("Xc ", **fmt) != NULL) | 1114 | opt = getoption(h, fmt, psize); |
1115 | } while (opt == Knop); /* skip no-op options */ | ||
1116 | align = *psize; /* usually, alignment follows size */ | ||
1117 | if (opt == Kpaddalign) { /* 'X' gets alignment from following option */ | ||
1118 | if (getoption(h, fmt, &align) == Kchar || align == 0) | ||
1123 | luaL_argerror(h->L, 1, "invalid next option for option 'X'"); | 1119 | luaL_argerror(h->L, 1, "invalid next option for option 'X'"); |
1124 | getoption(h, fmt, &align); /* get next element's size for alignment */ | ||
1125 | } | 1120 | } |
1126 | if (align <= 1 || opt == Kchar) /* need no alignment? */ | 1121 | if (align <= 1 || opt == Kchar) /* need no alignment? */ |
1127 | *ntoalign = 0; | 1122 | *ntoalign = 0; |
1128 | else { | 1123 | else { |
1129 | if (align > h->maxalign) | 1124 | if (align > h->maxalign) /* enforce maximum alignment */ |
1130 | align = h->maxalign; | 1125 | align = h->maxalign; |
1131 | if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ | 1126 | if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ |
1132 | luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); | 1127 | luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); |
@@ -1173,10 +1168,10 @@ static int str_pack (lua_State *L) { | |||
1173 | const char *fmt = luaL_checkstring(L, 1); /* format string */ | 1168 | const char *fmt = luaL_checkstring(L, 1); /* format string */ |
1174 | int arg = 1; /* current argument to pack */ | 1169 | int arg = 1; /* current argument to pack */ |
1175 | size_t totalsize = 0; /* accumulate total size of result */ | 1170 | size_t totalsize = 0; /* accumulate total size of result */ |
1176 | getheader(L, &h, &fmt); | 1171 | initheader(L, &h); |
1177 | lua_pushnil(L); /* mark to separate arguments from string buffer */ | 1172 | lua_pushnil(L); /* mark to separate arguments from string buffer */ |
1178 | luaL_buffinit(L, &b); | 1173 | luaL_buffinit(L, &b); |
1179 | while (*fmt != '\0') { | 1174 | for (;;) { |
1180 | int size, ntoalign; | 1175 | int size, ntoalign; |
1181 | KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); | 1176 | KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); |
1182 | totalsize += ntoalign + size; | 1177 | totalsize += ntoalign + size; |
@@ -1231,7 +1226,7 @@ static int str_pack (lua_State *L) { | |||
1231 | totalsize += len; | 1226 | totalsize += len; |
1232 | break; | 1227 | break; |
1233 | } | 1228 | } |
1234 | case Kstring0: { /* zero-terminated string */ | 1229 | case Kzstr: { /* zero-terminated string */ |
1235 | size_t len; | 1230 | size_t len; |
1236 | const char *s = luaL_checklstring(L, arg, &len); | 1231 | const char *s = luaL_checklstring(L, arg, &len); |
1237 | luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); | 1232 | luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); |
@@ -1241,13 +1236,14 @@ static int str_pack (lua_State *L) { | |||
1241 | break; | 1236 | break; |
1242 | } | 1237 | } |
1243 | case Kpadding: luaL_addchar(&b, '\0'); /* go through */ | 1238 | case Kpadding: luaL_addchar(&b, '\0'); /* go through */ |
1244 | case Kpaddalig: case Kspace: | 1239 | case Kpaddalign: case Knop: |
1245 | arg--; /* undo increment */ | 1240 | arg--; /* undo increment */ |
1246 | break; | 1241 | break; |
1242 | case Keof: /* end of format */ | ||
1243 | luaL_pushresult(&b); | ||
1244 | return 1; | ||
1247 | } | 1245 | } |
1248 | } | 1246 | } |
1249 | luaL_pushresult(&b); | ||
1250 | return 1; | ||
1251 | } | 1247 | } |
1252 | 1248 | ||
1253 | 1249 | ||
@@ -1285,8 +1281,8 @@ static int str_unpack (lua_State *L) { | |||
1285 | size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; | 1281 | size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; |
1286 | int n = 0; /* number of results */ | 1282 | int n = 0; /* number of results */ |
1287 | luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); | 1283 | luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); |
1288 | getheader(L, &h, &fmt); | 1284 | initheader(L, &h); |
1289 | while (*fmt) { | 1285 | for (;;) { |
1290 | int size, ntoalign; | 1286 | int size, ntoalign; |
1291 | KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); | 1287 | KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); |
1292 | if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) | 1288 | if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) |
@@ -1324,20 +1320,21 @@ static int str_unpack (lua_State *L) { | |||
1324 | pos += len; | 1320 | pos += len; |
1325 | break; | 1321 | break; |
1326 | } | 1322 | } |
1327 | case Kstring0: { | 1323 | case Kzstr: { |
1328 | size_t len = (int)strlen(data + pos); | 1324 | size_t len = (int)strlen(data + pos); |
1329 | lua_pushlstring(L, data + pos, len); | 1325 | lua_pushlstring(L, data + pos, len); |
1330 | pos += len + 1; /* skip final '\0' */ | 1326 | pos += len + 1; /* skip final '\0' */ |
1331 | break; | 1327 | break; |
1332 | } | 1328 | } |
1333 | case Kpaddalig: case Kpadding: case Kspace: | 1329 | case Kpaddalign: case Kpadding: case Knop: |
1334 | n--; /* undo increment */ | 1330 | n--; /* undo increment */ |
1335 | break; | 1331 | break; |
1332 | case Keof: /* end of format */ | ||
1333 | lua_pushinteger(L, pos + 1); /* next position */ | ||
1334 | return n; | ||
1336 | } | 1335 | } |
1337 | pos += size; | 1336 | pos += size; |
1338 | } | 1337 | } |
1339 | lua_pushinteger(L, pos + 1); /* next position */ | ||
1340 | return n + 1; | ||
1341 | } | 1338 | } |
1342 | 1339 | ||
1343 | /* }====================================================== */ | 1340 | /* }====================================================== */ |