aboutsummaryrefslogtreecommitdiff
path: root/lstrlib.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2014-10-20 14:44:54 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2014-10-20 14:44:54 -0200
commit57559547a30164e60ffa05422f9db990517dbcc5 (patch)
tree9abc4290cd0ad3e223be0f85b8717a0081ee6d55 /lstrlib.c
parentcfa84e123272acff178fe2e4cf5af7ec20e56572 (diff)
downloadlua-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.c107
1 files changed, 52 insertions, 55 deletions
diff --git a/lstrlib.c b/lstrlib.c
index f1239df5..28e7355a 100644
--- a/lstrlib.c
+++ b/lstrlib.c
@@ -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
1003typedef enum KOption {Kint, Kuint, Kfloat, Kchar, Kstring, Kstring0, 1003/*
1004 Kspace, Kpadding, Kpaddalig} KOption; 1004** options for pack/unpack
1005*/
1006typedef 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*/
1042static 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*/
1053static 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*/
1066static void getheader (lua_State *L, Header *h, const char **fmt) { 1054static 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*/
1076static KOption getoption (Header *h, const char **fmt, int *size) { 1064static 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*/
1117static KOption getdetails (Header *h, size_t totalsize, 1109static 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/* }====================================================== */