]> git.saurik.com Git - redis.git/blame - deps/lua/src/lua_struct.c
redis-cli pipe mode: handle EAGAIN while writing to socket.
[redis.git] / deps / lua / src / lua_struct.c
CommitLineData
2f75bbab 1
2#include <assert.h>
3#include <ctype.h>
4#include <limits.h>
5#include <string.h>
6
7
8#include "lua.h"
9#include "lauxlib.h"
10
11
12/*
13** {======================================================
14** Library for packing/unpacking structures.
15** $Id: struct.c,v 1.2 2008/04/18 20:06:01 roberto Exp $
16** See Copyright Notice at the end of this file
17** =======================================================
18*/
19/*
20** Valid formats:
21** > - big endian
22** < - little endian
23** ![num] - alignment
24** x - pading
25** b/B - signed/unsigned byte
26** h/H - signed/unsigned short
27** l/L - signed/unsigned long
28** i/In - signed/unsigned integer with size `n' (default is size of int)
29** cn - sequence of `n' chars (from/to a string); when packing, n==0 means
30 the whole string; when unpacking, n==0 means use the previous
31 read number as the string length
32** s - zero-terminated string
33** f - float
34** d - double
35** ' ' - ignored
36*/
37
38
39/* is 'x' a power of 2? */
40#define isp2(x) ((x) > 0 && ((x) & ((x) - 1)) == 0)
41
42/* dummy structure to get alignment requirements */
43struct cD {
44 char c;
45 double d;
46};
47
48
49#define PADDING (sizeof(struct cD) - sizeof(double))
50#define MAXALIGN (PADDING > sizeof(int) ? PADDING : sizeof(int))
51
52
53/* endian options */
54#define BIG 0
55#define LITTLE 1
56
57
58static union {
59 int dummy;
60 char endian;
61} const native = {1};
62
63
64typedef struct Header {
65 int endian;
66 int align;
67} Header;
68
69
70static size_t getnum (const char **fmt, size_t df) {
71 if (!isdigit(**fmt)) /* no number? */
72 return df; /* return default value */
73 else {
74 size_t a = 0;
75 do {
76 a = a*10 + *((*fmt)++) - '0';
77 } while (isdigit(**fmt));
78 return a;
79 }
80}
81
82
83#define defaultoptions(h) ((h)->endian = native.endian, (h)->align = 1)
84
85
86
87static size_t optsize (lua_State *L, char opt, const char **fmt) {
88 switch (opt) {
89 case 'B': case 'b': return sizeof(char);
90 case 'H': case 'h': return sizeof(short);
91 case 'L': case 'l': return sizeof(long);
92 case 'f': return sizeof(float);
93 case 'd': return sizeof(double);
94 case 'x': return 1;
95 case 'c': return getnum(fmt, 1);
96 case 's': case ' ': case '<': case '>': case '!': return 0;
97 case 'i': case 'I': {
98 int sz = getnum(fmt, sizeof(int));
99 if (!isp2(sz))
100 luaL_error(L, "integral size %d is not a power of 2", sz);
101 return sz;
102 }
103 default: {
104 const char *msg = lua_pushfstring(L, "invalid format option [%c]", opt);
105 return luaL_argerror(L, 1, msg);
106 }
107 }
108}
109
110
111static int gettoalign (size_t len, Header *h, int opt, size_t size) {
112 if (size == 0 || opt == 'c') return 0;
113 if (size > (size_t)h->align) size = h->align; /* respect max. alignment */
114 return (size - (len & (size - 1))) & (size - 1);
115}
116
117
118static void commoncases (lua_State *L, int opt, const char **fmt, Header *h) {
119 switch (opt) {
120 case ' ': return; /* ignore white spaces */
121 case '>': h->endian = BIG; return;
122 case '<': h->endian = LITTLE; return;
123 case '!': {
124 int a = getnum(fmt, MAXALIGN);
125 if (!isp2(a))
126 luaL_error(L, "alignment %d is not a power of 2", a);
127 h->align = a;
128 return;
129 }
130 default: assert(0);
131 }
132}
133
134
135static void putinteger (lua_State *L, luaL_Buffer *b, int arg, int endian,
136 int size) {
137 lua_Number n = luaL_checknumber(L, arg);
138 unsigned long value;
139 if (n < (lua_Number)LONG_MAX)
140 value = (long)n;
141 else
142 value = (unsigned long)n;
143 if (endian == LITTLE) {
144 int i;
145 for (i = 0; i < size; i++)
146 luaL_addchar(b, (value >> 8*i) & 0xff);
147 }
148 else {
149 int i;
150 for (i = size - 1; i >= 0; i--)
151 luaL_addchar(b, (value >> 8*i) & 0xff);
152 }
153}
154
155
156static void correctbytes (char *b, int size, int endian) {
157 if (endian != native.endian) {
158 int i = 0;
159 while (i < --size) {
160 char temp = b[i];
161 b[i++] = b[size];
162 b[size] = temp;
163 }
164 }
165}
166
167
168static int b_pack (lua_State *L) {
169 luaL_Buffer b;
170 const char *fmt = luaL_checkstring(L, 1);
171 Header h;
172 int arg = 2;
173 size_t totalsize = 0;
174 defaultoptions(&h);
175 lua_pushnil(L); /* mark to separate arguments from string buffer */
176 luaL_buffinit(L, &b);
177 while (*fmt != '\0') {
178 int opt = *fmt++;
179 size_t size = optsize(L, opt, &fmt);
180 int toalign = gettoalign(totalsize, &h, opt, size);
181 totalsize += toalign;
182 while (toalign-- > 0) luaL_putchar(&b, '\0');
183 switch (opt) {
184 case 'b': case 'B': case 'h': case 'H':
185 case 'l': case 'L': case 'i': case 'I': { /* integer types */
186 putinteger(L, &b, arg++, h.endian, size);
187 break;
188 }
189 case 'x': {
190 luaL_putchar(&b, '\0');
191 break;
192 }
193 case 'f': {
194 float f = (float)luaL_checknumber(L, arg++);
195 correctbytes((char *)&f, size, h.endian);
196 luaL_addlstring(&b, (char *)&f, size);
197 break;
198 }
199 case 'd': {
200 double d = luaL_checknumber(L, arg++);
201 correctbytes((char *)&d, size, h.endian);
202 luaL_addlstring(&b, (char *)&d, size);
203 break;
204 }
205 case 'c': case 's': {
206 size_t l;
207 const char *s = luaL_checklstring(L, arg++, &l);
208 if (size == 0) size = l;
209 luaL_argcheck(L, l >= (size_t)size, arg, "string too short");
210 luaL_addlstring(&b, s, size);
211 if (opt == 's') {
212 luaL_putchar(&b, '\0'); /* add zero at the end */
213 size++;
214 }
215 break;
216 }
217 default: commoncases(L, opt, &fmt, &h);
218 }
219 totalsize += size;
220 }
221 luaL_pushresult(&b);
222 return 1;
223}
224
225
226static lua_Number getinteger (const char *buff, int endian,
227 int issigned, int size) {
228 unsigned long l = 0;
229 if (endian == BIG) {
230 int i;
231 for (i = 0; i < size; i++)
232 l |= (unsigned long)(unsigned char)buff[size - i - 1] << (i*8);
233 }
234 else {
235 int i;
236 for (i = 0; i < size; i++)
237 l |= (unsigned long)(unsigned char)buff[i] << (i*8);
238 }
239 if (!issigned)
240 return (lua_Number)l;
241 else { /* signed format */
242 unsigned long mask = ~(0UL) << (size*8 - 1);
243 if (l & mask) /* negative value? */
244 l |= mask; /* signal extension */
245 return (lua_Number)(long)l;
246 }
247}
248
249
250static int b_unpack (lua_State *L) {
251 Header h;
252 const char *fmt = luaL_checkstring(L, 1);
253 size_t ld;
254 const char *data = luaL_checklstring(L, 2, &ld);
255 size_t pos = luaL_optinteger(L, 3, 1) - 1;
256 defaultoptions(&h);
257 lua_settop(L, 2);
258 while (*fmt) {
259 int opt = *fmt++;
260 size_t size = optsize(L, opt, &fmt);
261 pos += gettoalign(pos, &h, opt, size);
262 luaL_argcheck(L, pos+size <= ld, 2, "data string too short");
263 switch (opt) {
264 case 'b': case 'B': case 'h': case 'H':
265 case 'l': case 'L': case 'i': case 'I': { /* integer types */
266 int issigned = islower(opt);
267 lua_Number res = getinteger(data+pos, h.endian, issigned, size);
268 lua_pushnumber(L, res);
269 break;
270 }
271 case 'x': {
272 break;
273 }
274 case 'f': {
275 float f;
276 memcpy(&f, data+pos, size);
277 correctbytes((char *)&f, sizeof(f), h.endian);
278 lua_pushnumber(L, f);
279 break;
280 }
281 case 'd': {
282 double d;
283 memcpy(&d, data+pos, size);
284 correctbytes((char *)&d, sizeof(d), h.endian);
285 lua_pushnumber(L, d);
286 break;
287 }
288 case 'c': {
289 if (size == 0) {
290 if (!lua_isnumber(L, -1))
291 luaL_error(L, "format `c0' needs a previous size");
292 size = lua_tonumber(L, -1);
293 lua_pop(L, 1);
294 luaL_argcheck(L, pos+size <= ld, 2, "data string too short");
295 }
296 lua_pushlstring(L, data+pos, size);
297 break;
298 }
299 case 's': {
300 const char *e = (const char *)memchr(data+pos, '\0', ld - pos);
301 if (e == NULL)
302 luaL_error(L, "unfinished string in data");
303 size = (e - (data+pos)) + 1;
304 lua_pushlstring(L, data+pos, size - 1);
305 break;
306 }
307 default: commoncases(L, opt, &fmt, &h);
308 }
309 pos += size;
310 }
311 lua_pushinteger(L, pos + 1);
312 return lua_gettop(L) - 2;
313}
314
315/* }====================================================== */
316
317
318
319static const struct luaL_reg thislib[] = {
320 {"pack", b_pack},
321 {"unpack", b_unpack},
322 {NULL, NULL}
323};
324
325
326LUALIB_API int luaopen_struct (lua_State *L) {
327 luaL_register(L, "struct", thislib);
328 return 1;
329}
330
331
332
333/******************************************************************************
334* Copyright (C) 2010 Lua.org, PUC-Rio. All rights reserved.
335*
336* Permission is hereby granted, free of charge, to any person obtaining
337* a copy of this software and associated documentation files (the
338* "Software"), to deal in the Software without restriction, including
339* without limitation the rights to use, copy, modify, merge, publish,
340* distribute, sublicense, and/or sell copies of the Software, and to
341* permit persons to whom the Software is furnished to do so, subject to
342* the following conditions:
343*
344* The above copyright notice and this permission notice shall be
345* included in all copies or substantial portions of the Software.
346*
347* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
348* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
349* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
350* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
351* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
352* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
353* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
354******************************************************************************/