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 | |
| 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')
| -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 | /* }====================================================== */ |
