Browse Source

in 'pack'/'unpack', endianness and alignment treated like options +

small changes in names and handling of internal options ('KOption')
pull/9/head
Roberto Ierusalimschy 10 years ago
parent
commit
57559547a3
  1. 107
      lstrlib.c

107
lstrlib.c

@ -1,5 +1,5 @@
/* /*
** $Id: lstrlib.c,v 1.203 2014/10/17 10:55:28 roberto Exp roberto $ ** $Id: lstrlib.c,v 1.204 2014/10/17 16:28:21 roberto Exp roberto $
** Standard library for string operations and pattern-matching ** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -1000,8 +1000,21 @@ typedef struct Header {
} Header; } Header;
typedef enum KOption {Kint, Kuint, Kfloat, Kchar, Kstring, Kstring0, /*
Kspace, Kpadding, Kpaddalig} KOption; ** options for pack/unpack
*/
typedef enum KOption {
Kint, /* signed integers */
Kuint, /* unsigned integers */
Kfloat, /* floating-point numbers */
Kchar, /* fixed-length strings */
Kstring, /* strings with prefixed length */
Kzstr, /* zero-terminated strings */
Kpadding, /* padding */
Kpaddalign, /* padding for alignment */
Knop, /* no-op (configuration or spaces) */
Keof /* end of format */
} KOption;
/* /*
@ -1036,37 +1049,12 @@ static int getnumlimit (Header *h, const char **fmt, int df) {
/* /*
** Reads an option endianness indication ('<'/'>') and ** Initialize Header
** returns true if operation should use little endian.
*/
static int getendian (const char **fmt) {
if (**fmt == '<' || **fmt == '>') /* explicit endianness? */
return (*((*fmt)++) == '<'); /* true iff little endian */
else /* no endian indication */
return nativeendian.little; /* use native */
}
/*
** Read and return maximum alignment to be used
*/
static int getalignment (Header *h, const char **fmt) {
if (**fmt == '!') { /* explicit alignment? */
(*fmt)++; /* skip '!' */
return getnumlimit(h, fmt, MAXALIGN);
}
else
return 1; /* default is no alignment */
}
/*
** Read optional endianness and alignment indications
*/ */
static void getheader (lua_State *L, Header *h, const char **fmt) { static void initheader (lua_State *L, Header *h) {
h->L = L; h->L = L;
h->islittle = getendian(fmt); h->islittle = nativeendian.little;
h->maxalign = getalignment(h, fmt); h->maxalign = 1;
} }
@ -1075,6 +1063,7 @@ static void getheader (lua_State *L, Header *h, const char **fmt) {
*/ */
static KOption getoption (Header *h, const char **fmt, int *size) { static KOption getoption (Header *h, const char **fmt, int *size) {
int opt = *((*fmt)++); int opt = *((*fmt)++);
*size = 0; /* default */
switch (opt) { switch (opt) {
case 'b': *size = sizeof(char); return Kint; case 'b': *size = sizeof(char); return Kint;
case 'B': *size = sizeof(char); return Kuint; case 'B': *size = sizeof(char); return Kuint;
@ -1092,14 +1081,17 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
case 'c': *size = getnum(fmt, 1); return Kchar; case 'c': *size = getnum(fmt, 1); return Kchar;
case 'z': *size = 0; return Kstring0; case 'z': return Kzstr;
case 'x': *size = 1; return Kpadding; case 'x': *size = 1; return Kpadding;
case 'X': *size = 0; return Kpaddalig; case 'X': return Kpaddalign;
case ' ': *size = 0; return Kspace; case ' ': return Knop;
case '\0': return Keof;
case '<': h->islittle = 1; return Knop;
case '>': h->islittle = 0; return Knop;
case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); return Knop;
default: { default: {
*size = 0; /* to avoid warnings */
luaL_error(h->L, "invalid format option '%c'", opt); luaL_error(h->L, "invalid format option '%c'", opt);
return (KOption)0; return Knop;
} }
} }
} }
@ -1116,17 +1108,20 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
*/ */
static KOption getdetails (Header *h, size_t totalsize, static KOption getdetails (Header *h, size_t totalsize,
const char **fmt, int *psize, int *ntoalign) { const char **fmt, int *psize, int *ntoalign) {
KOption opt = getoption(h, fmt, psize); int align;
int align = *psize; /* usually, alignment follows size */ KOption opt;
if (opt == Kpaddalig) { do {
if (**fmt == '\0' || strchr("Xc ", **fmt) != NULL) opt = getoption(h, fmt, psize);
} while (opt == Knop); /* skip no-op options */
align = *psize; /* usually, alignment follows size */
if (opt == Kpaddalign) { /* 'X' gets alignment from following option */
if (getoption(h, fmt, &align) == Kchar || align == 0)
luaL_argerror(h->L, 1, "invalid next option for option 'X'"); luaL_argerror(h->L, 1, "invalid next option for option 'X'");
getoption(h, fmt, &align); /* get next element's size for alignment */
} }
if (align <= 1 || opt == Kchar) /* need no alignment? */ if (align <= 1 || opt == Kchar) /* need no alignment? */
*ntoalign = 0; *ntoalign = 0;
else { else {
if (align > h->maxalign) if (align > h->maxalign) /* enforce maximum alignment */
align = h->maxalign; align = h->maxalign;
if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */
luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); luaL_argerror(h->L, 1, "format asks for alignment not power of 2");
@ -1173,10 +1168,10 @@ static int str_pack (lua_State *L) {
const char *fmt = luaL_checkstring(L, 1); /* format string */ const char *fmt = luaL_checkstring(L, 1); /* format string */
int arg = 1; /* current argument to pack */ int arg = 1; /* current argument to pack */
size_t totalsize = 0; /* accumulate total size of result */ size_t totalsize = 0; /* accumulate total size of result */
getheader(L, &h, &fmt); initheader(L, &h);
lua_pushnil(L); /* mark to separate arguments from string buffer */ lua_pushnil(L); /* mark to separate arguments from string buffer */
luaL_buffinit(L, &b); luaL_buffinit(L, &b);
while (*fmt != '\0') { for (;;) {
int size, ntoalign; int size, ntoalign;
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
totalsize += ntoalign + size; totalsize += ntoalign + size;
@ -1231,7 +1226,7 @@ static int str_pack (lua_State *L) {
totalsize += len; totalsize += len;
break; break;
} }
case Kstring0: { /* zero-terminated string */ case Kzstr: { /* zero-terminated string */
size_t len; size_t len;
const char *s = luaL_checklstring(L, arg, &len); const char *s = luaL_checklstring(L, arg, &len);
luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros");
@ -1241,13 +1236,14 @@ static int str_pack (lua_State *L) {
break; break;
} }
case Kpadding: luaL_addchar(&b, '\0'); /* go through */ case Kpadding: luaL_addchar(&b, '\0'); /* go through */
case Kpaddalig: case Kspace: case Kpaddalign: case Knop:
arg--; /* undo increment */ arg--; /* undo increment */
break; break;
case Keof: /* end of format */
luaL_pushresult(&b);
return 1;
} }
} }
luaL_pushresult(&b);
return 1;
} }
@ -1285,8 +1281,8 @@ static int str_unpack (lua_State *L) {
size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1;
int n = 0; /* number of results */ int n = 0; /* number of results */
luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); luaL_argcheck(L, pos <= ld, 3, "initial position out of string");
getheader(L, &h, &fmt); initheader(L, &h);
while (*fmt) { for (;;) {
int size, ntoalign; int size, ntoalign;
KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign);
if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld)
@ -1324,20 +1320,21 @@ static int str_unpack (lua_State *L) {
pos += len; pos += len;
break; break;
} }
case Kstring0: { case Kzstr: {
size_t len = (int)strlen(data + pos); size_t len = (int)strlen(data + pos);
lua_pushlstring(L, data + pos, len); lua_pushlstring(L, data + pos, len);
pos += len + 1; /* skip final '\0' */ pos += len + 1; /* skip final '\0' */
break; break;
} }
case Kpaddalig: case Kpadding: case Kspace: case Kpaddalign: case Kpadding: case Knop:
n--; /* undo increment */ n--; /* undo increment */
break; break;
case Keof: /* end of format */
lua_pushinteger(L, pos + 1); /* next position */
return n;
} }
pos += size; pos += size;
} }
lua_pushinteger(L, pos + 1); /* next position */
return n + 1;
} }
/* }====================================================== */ /* }====================================================== */

Loading…
Cancel
Save