mirror of
https://github.com/love2d/love.git
synced 2026-08-17 11:00:31 +02:00
603 lines
19 KiB
C
603 lines
19 KiB
C
/*
|
|
** $Id: lstrlib.c,v 1.254 2016/12/22 13:08:50 roberto Exp $
|
|
** Standard library for string operations and pattern-matching
|
|
** Modified by the Kepler Project and the LOVE Development Team to work with
|
|
** Lua 5.1's API
|
|
*/
|
|
|
|
/*********************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2015 Kepler Project.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
* this software and associated documentation files (the "Software"), to deal in
|
|
* the Software without restriction, including without limitation the rights to
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
* subject to the following conditions:
|
|
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*********************************************************************/
|
|
|
|
/*********************************************************************
|
|
* This file contains parts of Lua 5.2's and Lua 5.3's source code:
|
|
*
|
|
* Copyright (C) 1994-2014 Lua.org, PUC-Rio.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*********************************************************************/
|
|
|
|
#include "lprefix.h"
|
|
|
|
|
|
#include <ctype.h>
|
|
#include <float.h>
|
|
#include <limits.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "lua.h"
|
|
|
|
#include "lauxlib.h"
|
|
#include "lualib.h"
|
|
#include "lstrlib.h"
|
|
|
|
#if LUA_VERSION_NUM == 501
|
|
typedef size_t lua_Unsigned;
|
|
#endif
|
|
|
|
#if LUA_VERSION_NUM >= 504
|
|
# define LUAL_BUFFER53_BUFFER(B) (B)->b.b
|
|
#elif LUA_VERSION_NUM == 501
|
|
# define LUAL_BUFFER53_BUFFER(B) (B)->b.buffer
|
|
#else
|
|
# define LUAL_BUFFER53_BUFFER(B) (B)->b.initb
|
|
#endif
|
|
|
|
static void luaL_buffinit_53 (lua_State *L, luaL_Buffer_53 *B) {
|
|
#if LUA_VERSION_NUM == 501
|
|
/* make it crash if used via pointer to a 5.1-style luaL_Buffer */
|
|
B->b.p = NULL;
|
|
B->b.L = NULL;
|
|
B->b.lvl = 0;
|
|
/* reuse the buffer from the 5.1-style luaL_Buffer though! */
|
|
B->ptr = B->b.buffer;
|
|
B->capacity = LUAL_BUFFERSIZE;
|
|
B->nelems = 0;
|
|
B->L2 = L;
|
|
#else
|
|
return luaL_buffinit(L, (luaL_Buffer*) B);
|
|
#endif
|
|
}
|
|
|
|
|
|
static char *luaL_prepbuffsize_53 (luaL_Buffer_53 *B, size_t s) {
|
|
#if LUA_VERSION_NUM == 501
|
|
if (B->capacity - B->nelems < s) { /* needs to grow */
|
|
char* newptr = NULL;
|
|
size_t newcap = B->capacity * 2;
|
|
if (newcap - B->nelems < s)
|
|
newcap = B->nelems + s;
|
|
if (newcap < B->capacity) /* overflow */
|
|
luaL_error(B->L2, "buffer too large");
|
|
newptr = (char*)lua_newuserdata(B->L2, newcap);
|
|
memcpy(newptr, B->ptr, B->nelems);
|
|
if (B->ptr != B->b.buffer)
|
|
lua_replace(B->L2, -2); /* remove old buffer */
|
|
B->ptr = newptr;
|
|
B->capacity = newcap;
|
|
}
|
|
return B->ptr+B->nelems;
|
|
#else
|
|
return luaL_prepbuffsize((luaL_Buffer*) B, s);
|
|
#endif
|
|
}
|
|
|
|
|
|
#define luaL_addsize_53(B, s) \
|
|
((B)->nelems += (s))
|
|
|
|
#define luaL_addchar_53(B, c) \
|
|
((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize_53((B), 1)), \
|
|
((B)->ptr[(B)->nelems++] = (c)))
|
|
|
|
|
|
static void luaL_addlstring_53 (luaL_Buffer_53 *B, const char *s, size_t l) {
|
|
memcpy(luaL_prepbuffsize_53(B, l), s, l);
|
|
luaL_addsize_53(B, l);
|
|
}
|
|
|
|
|
|
void lua53_pushresult (luaL_Buffer_53 *B) {
|
|
lua_pushlstring(B->L2, B->ptr, B->nelems);
|
|
if (B->ptr != LUAL_BUFFER53_BUFFER(B))
|
|
lua_replace(B->L2, -2); /* remove userdata buffer */
|
|
}
|
|
|
|
void lua53_cleanupbuffer (luaL_Buffer_53 *B) {
|
|
if (B->ptr != LUAL_BUFFER53_BUFFER(B))
|
|
lua_replace(B->L2, -1); /* remove userdata buffer */
|
|
}
|
|
|
|
/*
|
|
** Some sizes are better limited to fit in 'int', but must also fit in
|
|
** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.)
|
|
*/
|
|
#define MAX_SIZET ((size_t)(~(size_t)0))
|
|
|
|
#define MAXSIZE \
|
|
(sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX))
|
|
|
|
|
|
/* translate a relative string position: negative means back from end */
|
|
static lua_Integer posrelat (lua_Integer pos, size_t len) {
|
|
if (pos >= 0) return pos;
|
|
else if (0u - (size_t)pos > len) return 0;
|
|
else return (lua_Integer)len + pos + 1;
|
|
}
|
|
|
|
|
|
/*
|
|
** {======================================================
|
|
** PACK/UNPACK
|
|
** =======================================================
|
|
*/
|
|
|
|
|
|
/* value used for padding */
|
|
#if !defined(LUAL_PACKPADBYTE)
|
|
#define LUAL_PACKPADBYTE 0x00
|
|
#endif
|
|
|
|
/* maximum size for the binary representation of an integer */
|
|
#define MAXINTSIZE 16
|
|
|
|
/* number of bits in a character */
|
|
#define NB CHAR_BIT
|
|
|
|
/* mask for one character (NB 1's) */
|
|
#define MC ((1 << NB) - 1)
|
|
|
|
/* size of a lua_Integer */
|
|
#define SZINT ((int)sizeof(lua_Integer))
|
|
|
|
|
|
/* dummy union to get native endianness */
|
|
static const union {
|
|
int dummy;
|
|
char little; /* true iff machine is little endian */
|
|
} nativeendian = {1};
|
|
|
|
|
|
/* dummy structure to get native alignment requirements */
|
|
struct cD {
|
|
char c;
|
|
union { double d; void *p; lua_Integer i; lua_Number n; } u;
|
|
};
|
|
|
|
#define MAXALIGN (offsetof(struct cD, u))
|
|
|
|
|
|
/*
|
|
** Union for serializing floats
|
|
*/
|
|
typedef union Ftypes {
|
|
float f;
|
|
double d;
|
|
lua_Number n;
|
|
char buff[5 * sizeof(lua_Number)]; /* enough for any float type */
|
|
} Ftypes;
|
|
|
|
|
|
/*
|
|
** information to pack/unpack stuff
|
|
*/
|
|
typedef struct Header {
|
|
lua_State *L;
|
|
int islittle;
|
|
int maxalign;
|
|
} Header;
|
|
|
|
|
|
/*
|
|
** 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) */
|
|
} KOption;
|
|
|
|
|
|
/*
|
|
** Read an integer numeral from string 'fmt' or return 'df' if
|
|
** there is no numeral
|
|
*/
|
|
static int digit (int c) { return '0' <= c && c <= '9'; }
|
|
|
|
static int getnum (const char **fmt, int df) {
|
|
if (!digit(**fmt)) /* no number? */
|
|
return df; /* return default value */
|
|
else {
|
|
int a = 0;
|
|
do {
|
|
a = a*10 + (*((*fmt)++) - '0');
|
|
} while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10);
|
|
return a;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
** Read an integer numeral and raises an error if it is larger
|
|
** than the maximum size for integers.
|
|
*/
|
|
static int getnumlimit (Header *h, const char **fmt, int df) {
|
|
int sz = getnum(fmt, df);
|
|
if (sz > MAXINTSIZE || sz <= 0)
|
|
luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
|
|
sz, MAXINTSIZE);
|
|
return sz;
|
|
}
|
|
|
|
|
|
/*
|
|
** Initialize Header
|
|
*/
|
|
static void initheader (lua_State *L, Header *h) {
|
|
h->L = L;
|
|
h->islittle = nativeendian.little;
|
|
h->maxalign = 1;
|
|
}
|
|
|
|
|
|
/*
|
|
** Read and classify next option. 'size' is filled with option's size.
|
|
*/
|
|
static KOption getoption (Header *h, const char **fmt, int *size) {
|
|
int opt = *((*fmt)++);
|
|
*size = 0; /* default */
|
|
switch (opt) {
|
|
case 'b': *size = sizeof(char); return Kint;
|
|
case 'B': *size = sizeof(char); return Kuint;
|
|
case 'h': *size = sizeof(short); return Kint;
|
|
case 'H': *size = sizeof(short); return Kuint;
|
|
case 'l': *size = sizeof(long); return Kint;
|
|
case 'L': *size = sizeof(long); return Kuint;
|
|
case 'j': *size = sizeof(lua_Integer); return Kint;
|
|
case 'J': *size = sizeof(lua_Integer); return Kuint;
|
|
case 'T': *size = sizeof(size_t); return Kuint;
|
|
case 'f': *size = sizeof(float); return Kfloat;
|
|
case 'd': *size = sizeof(double); return Kfloat;
|
|
case 'n': *size = sizeof(lua_Number); return Kfloat;
|
|
case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint;
|
|
case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
|
|
case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
|
|
case 'c':
|
|
*size = getnum(fmt, -1);
|
|
if (*size == -1)
|
|
luaL_error(h->L, "missing size for format option 'c'");
|
|
return Kchar;
|
|
case 'z': return Kzstr;
|
|
case 'x': *size = 1; return Kpadding;
|
|
case 'X': return Kpaddalign;
|
|
case ' ': break;
|
|
case '<': h->islittle = 1; break;
|
|
case '>': h->islittle = 0; break;
|
|
case '=': h->islittle = nativeendian.little; break;
|
|
case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break;
|
|
default: luaL_error(h->L, "invalid format option '%c'", opt);
|
|
}
|
|
return Knop;
|
|
}
|
|
|
|
|
|
/*
|
|
** Read, classify, and fill other details about the next option.
|
|
** 'psize' is filled with option's size, 'notoalign' with its
|
|
** alignment requirements.
|
|
** Local variable 'size' gets the size to be aligned. (Kpadal option
|
|
** always gets its full alignment, other options are limited by
|
|
** the maximum alignment ('maxalign'). Kchar option needs no alignment
|
|
** despite its size.
|
|
*/
|
|
static KOption getdetails (Header *h, size_t totalsize,
|
|
const char **fmt, int *psize, int *ntoalign) {
|
|
KOption opt = getoption(h, fmt, psize);
|
|
int align = *psize; /* usually, alignment follows size */
|
|
if (opt == Kpaddalign) { /* 'X' gets alignment from following option */
|
|
if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0)
|
|
luaL_argerror(h->L, 1, "invalid next option for option 'X'");
|
|
}
|
|
if (align <= 1 || opt == Kchar) /* need no alignment? */
|
|
*ntoalign = 0;
|
|
else {
|
|
if (align > h->maxalign) /* enforce maximum alignment */
|
|
align = h->maxalign;
|
|
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");
|
|
*ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1);
|
|
}
|
|
return opt;
|
|
}
|
|
|
|
|
|
/*
|
|
** Pack integer 'n' with 'size' bytes and 'islittle' endianness.
|
|
** The final 'if' handles the case when 'size' is larger than
|
|
** the size of a Lua integer, correcting the extra sign-extension
|
|
** bytes if necessary (by default they would be zeros).
|
|
*/
|
|
static void packint (luaL_Buffer_53 *b, lua_Unsigned n,
|
|
int islittle, int size, int neg) {
|
|
char *buff = luaL_prepbuffsize_53(b, size);
|
|
int i;
|
|
buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */
|
|
for (i = 1; i < size; i++) {
|
|
n >>= NB;
|
|
buff[islittle ? i : size - 1 - i] = (char)(n & MC);
|
|
}
|
|
if (neg && size > SZINT) { /* negative number need sign extension? */
|
|
for (i = SZINT; i < size; i++) /* correct extra bytes */
|
|
buff[islittle ? i : size - 1 - i] = (char)MC;
|
|
}
|
|
luaL_addsize_53(b, size); /* add result to buffer */
|
|
}
|
|
|
|
|
|
/*
|
|
** Copy 'size' bytes from 'src' to 'dest', correcting endianness if
|
|
** given 'islittle' is different from native endianness.
|
|
*/
|
|
static void copywithendian (volatile char *dest, volatile const char *src,
|
|
int size, int islittle) {
|
|
if (islittle == nativeendian.little) {
|
|
while (size-- != 0)
|
|
*(dest++) = *(src++);
|
|
}
|
|
else {
|
|
dest += size - 1;
|
|
while (size-- != 0)
|
|
*(dest--) = *(src++);
|
|
}
|
|
}
|
|
|
|
|
|
void lua53_str_pack (lua_State *L, const char *fmt, int startidx, luaL_Buffer_53 *b) {
|
|
Header h;
|
|
int arg = startidx - 1; /* current argument to pack */
|
|
size_t totalsize = 0; /* accumulate total size of result */
|
|
initheader(L, &h);
|
|
lua_pushnil(L); /* mark to separate arguments from string buffer */
|
|
luaL_buffinit_53(L, b);
|
|
while (*fmt != '\0') {
|
|
int size, ntoalign;
|
|
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
|
|
totalsize += ntoalign + size;
|
|
while (ntoalign-- > 0)
|
|
luaL_addchar_53(b, LUAL_PACKPADBYTE); /* fill alignment */
|
|
arg++;
|
|
switch (opt) {
|
|
case Kint: { /* signed integers */
|
|
lua_Integer n = luaL_checkinteger(L, arg);
|
|
if (size < SZINT) { /* need overflow check? */
|
|
lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1);
|
|
luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow");
|
|
}
|
|
packint(b, (lua_Unsigned)n, h.islittle, size, (n < 0));
|
|
break;
|
|
}
|
|
case Kuint: { /* unsigned integers */
|
|
lua_Integer n = luaL_checkinteger(L, arg);
|
|
if (size < SZINT) /* need overflow check? */
|
|
luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)),
|
|
arg, "unsigned overflow");
|
|
packint(b, (lua_Unsigned)n, h.islittle, size, 0);
|
|
break;
|
|
}
|
|
case Kfloat: { /* floating-point options */
|
|
volatile Ftypes u;
|
|
char *buff = luaL_prepbuffsize_53(b, size);
|
|
lua_Number n = luaL_checknumber(L, arg); /* get argument */
|
|
if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */
|
|
else if (size == sizeof(u.d)) u.d = (double)n;
|
|
else u.n = n;
|
|
/* move 'u' to final result, correcting endianness if needed */
|
|
copywithendian(buff, u.buff, size, h.islittle);
|
|
luaL_addsize_53(b, size);
|
|
break;
|
|
}
|
|
case Kchar: { /* fixed-size string */
|
|
size_t len;
|
|
const char *s = luaL_checklstring(L, arg, &len);
|
|
luaL_argcheck(L, len <= (size_t)size, arg,
|
|
"string longer than given size");
|
|
luaL_addlstring_53(b, s, len); /* add string */
|
|
while (len++ < (size_t)size) /* pad extra space */
|
|
luaL_addchar_53(b, LUAL_PACKPADBYTE);
|
|
break;
|
|
}
|
|
case Kstring: { /* strings with length count */
|
|
size_t len;
|
|
const char *s = luaL_checklstring(L, arg, &len);
|
|
luaL_argcheck(L, size >= (int)sizeof(size_t) ||
|
|
len < ((size_t)1 << (size * NB)),
|
|
arg, "string length does not fit in given size");
|
|
packint(b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */
|
|
luaL_addlstring_53(b, s, len);
|
|
totalsize += len;
|
|
break;
|
|
}
|
|
case Kzstr: { /* zero-terminated string */
|
|
size_t len;
|
|
const char *s = luaL_checklstring(L, arg, &len);
|
|
luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros");
|
|
luaL_addlstring_53(b, s, len);
|
|
luaL_addchar_53(b, '\0'); /* add zero at the end */
|
|
totalsize += len + 1;
|
|
break;
|
|
}
|
|
case Kpadding: luaL_addchar_53(b, LUAL_PACKPADBYTE); /* FALLTHROUGH */
|
|
case Kpaddalign: case Knop:
|
|
arg--; /* undo increment */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int lua53_str_packsize (lua_State *L) {
|
|
Header h;
|
|
const char *fmt = luaL_checkstring(L, 1); /* format string */
|
|
size_t totalsize = 0; /* accumulate total size of result */
|
|
initheader(L, &h);
|
|
while (*fmt != '\0') {
|
|
int size, ntoalign;
|
|
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
|
|
size += ntoalign; /* total space used by option */
|
|
luaL_argcheck(L, totalsize <= MAXSIZE - size, 1,
|
|
"format result too large");
|
|
totalsize += size;
|
|
switch (opt) {
|
|
case Kstring: /* strings with length count */
|
|
case Kzstr: /* zero-terminated string */
|
|
luaL_argerror(L, 1, "variable-length format");
|
|
/* call never return, but to avoid warnings: *//* FALLTHROUGH */
|
|
default: break;
|
|
}
|
|
}
|
|
lua_pushinteger(L, (lua_Integer)totalsize);
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
** Unpack an integer with 'size' bytes and 'islittle' endianness.
|
|
** If size is smaller than the size of a Lua integer and integer
|
|
** is signed, must do sign extension (propagating the sign to the
|
|
** higher bits); if size is larger than the size of a Lua integer,
|
|
** it must check the unread bytes to see whether they do not cause an
|
|
** overflow.
|
|
*/
|
|
static lua_Integer unpackint (lua_State *L, const char *str,
|
|
int islittle, int size, int issigned) {
|
|
lua_Unsigned res = 0;
|
|
int i;
|
|
int limit = (size <= SZINT) ? size : SZINT;
|
|
for (i = limit - 1; i >= 0; i--) {
|
|
res <<= NB;
|
|
res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i];
|
|
}
|
|
if (size < SZINT) { /* real size smaller than lua_Integer? */
|
|
if (issigned) { /* needs sign extension? */
|
|
lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1);
|
|
res = ((res ^ mask) - mask); /* do sign extension */
|
|
}
|
|
}
|
|
else if (size > SZINT) { /* must check unread bytes */
|
|
int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC;
|
|
for (i = limit; i < size; i++) {
|
|
if ((unsigned char)str[islittle ? i : size - 1 - i] != mask)
|
|
luaL_error(L, "%d-byte integer does not fit into Lua Integer", size);
|
|
}
|
|
}
|
|
return (lua_Integer)res;
|
|
}
|
|
|
|
|
|
int lua53_str_unpack (lua_State *L, const char *fmt, const char *data, size_t ld, int dataidx, int posidx) {
|
|
Header h;
|
|
size_t pos = (size_t)posrelat(luaL_optinteger(L, posidx, 1), ld) - 1;
|
|
int n = 0; /* number of results */
|
|
luaL_argcheck(L, pos <= ld, posidx, "initial position out of string");
|
|
initheader(L, &h);
|
|
while (*fmt != '\0') {
|
|
int size, ntoalign;
|
|
KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign);
|
|
if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld)
|
|
luaL_argerror(L, dataidx, "data string too short");
|
|
pos += ntoalign; /* skip alignment */
|
|
/* stack space for item + next position */
|
|
luaL_checkstack(L, dataidx, "too many results");
|
|
n++;
|
|
switch (opt) {
|
|
case Kint:
|
|
case Kuint: {
|
|
lua_Integer res = unpackint(L, data + pos, h.islittle, size,
|
|
(opt == Kint));
|
|
lua_pushinteger(L, res);
|
|
break;
|
|
}
|
|
case Kfloat: {
|
|
volatile Ftypes u;
|
|
lua_Number num;
|
|
copywithendian(u.buff, data + pos, size, h.islittle);
|
|
if (size == sizeof(u.f)) num = (lua_Number)u.f;
|
|
else if (size == sizeof(u.d)) num = (lua_Number)u.d;
|
|
else num = u.n;
|
|
lua_pushnumber(L, num);
|
|
break;
|
|
}
|
|
case Kchar: {
|
|
lua_pushlstring(L, data + pos, size);
|
|
break;
|
|
}
|
|
case Kstring: {
|
|
size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0);
|
|
luaL_argcheck(L, pos + len + size <= ld, dataidx, "data string too short");
|
|
lua_pushlstring(L, data + pos + size, len);
|
|
pos += len; /* skip string */
|
|
break;
|
|
}
|
|
case Kzstr: {
|
|
size_t len = (int)strlen(data + pos);
|
|
lua_pushlstring(L, data + pos, len);
|
|
pos += len + 1; /* skip string plus final '\0' */
|
|
break;
|
|
}
|
|
case Kpaddalign: case Kpadding: case Knop:
|
|
n--; /* undo increment */
|
|
break;
|
|
}
|
|
pos += size;
|
|
}
|
|
lua_pushinteger(L, pos + 1); /* next position */
|
|
return n + 1;
|
|
}
|
|
|
|
/* }====================================================== */
|
|
|