aboutsummaryrefslogtreecommitdiff
path: root/src/lib_buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib_buffer.c')
-rw-r--r--src/lib_buffer.c278
1 files changed, 277 insertions, 1 deletions
diff --git a/src/lib_buffer.c b/src/lib_buffer.c
index c9ef9510..78c4eeb9 100644
--- a/src/lib_buffer.c
+++ b/src/lib_buffer.c
@@ -14,14 +14,286 @@
14 14
15#if LJ_HASBUFFER 15#if LJ_HASBUFFER
16#include "lj_gc.h" 16#include "lj_gc.h"
17#include "lj_err.h"
17#include "lj_buf.h" 18#include "lj_buf.h"
19#include "lj_str.h"
20#include "lj_tab.h"
21#include "lj_udata.h"
22#include "lj_meta.h"
23#if LJ_HASFFI
24#include "lj_ctype.h"
25#include "lj_cdata.h"
26#include "lj_cconv.h"
27#endif
28#include "lj_strfmt.h"
18#include "lj_serialize.h" 29#include "lj_serialize.h"
19#include "lj_lib.h" 30#include "lj_lib.h"
20 31
21/* ------------------------------------------------------------------------ */ 32/* ------------------------------------------------------------------------ */
22 33
34#define LJLIB_MODULE_buffer_method
35
36/* Check that the first argument is a string buffer. */
37static SBufExt *buffer_tobuf(lua_State *L)
38{
39 if (!(L->base < L->top && tvisbuf(L->base)))
40 lj_err_argtype(L, 1, "buffer");
41 return bufV(L->base);
42}
43
44/* Ditto, but for writers. */
45static LJ_AINLINE SBufExt *buffer_tobufw(lua_State *L)
46{
47 SBufExt *sbx = buffer_tobuf(L);
48 setsbufXL_(sbx, L);
49 return sbx;
50}
51
52LJLIB_CF(buffer_method_free)
53{
54 SBufExt *sbx = buffer_tobuf(L);
55 lj_bufx_free(G(L), sbx);
56 lj_bufx_init(L, sbx);
57 L->top = L->base+1; /* Chain buffer object. */
58 return 1;
59}
60
61LJLIB_CF(buffer_method_reset)
62{
63 SBufExt *sbx = buffer_tobuf(L);
64 lj_bufx_reset(sbx);
65 L->top = L->base+1; /* Chain buffer object. */
66 return 1;
67}
68
69LJLIB_CF(buffer_method_skip)
70{
71 SBufExt *sbx = buffer_tobuf(L);
72 MSize n = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
73 MSize len = sbufxlen(sbx);
74 if (n < len) {
75 sbx->r += n;
76 } else {
77 sbx->r = sbx->w = sbx->b;
78 }
79 L->top = L->base+1; /* Chain buffer object. */
80 return 1;
81}
82
83LJLIB_CF(buffer_method_set)
84{
85 SBufExt *sbx = buffer_tobuf(L);
86 const char *p;
87 MSize len;
88#if LJ_HASFFI
89 if (tviscdata(L->base+1)) {
90 CTState *cts = ctype_cts(L);
91 lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
92 L->base+1, CCF_ARG(2));
93 len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
94 } else
95#endif
96 {
97 GCstr *str = lj_lib_checkstrx(L, 2);
98 p = strdata(str);
99 len = str->len;
100 }
101 lj_bufx_free(G(L), sbx);
102 lj_bufx_init_cow(L, sbx, p, len);
103 setgcref(sbx->cowref, gcV(L->base+1));
104 L->top = L->base+1; /* Chain buffer object. */
105 return 1;
106}
107
108LJLIB_CF(buffer_method_put)
109{
110 SBufExt *sbx = buffer_tobufw(L);
111 ptrdiff_t arg, narg = L->top - L->base;
112 for (arg = 1; arg < narg; arg++) {
113 cTValue *o = &L->base[arg], *mo = NULL;
114 retry:
115 if (tvisstr(o)) {
116 lj_buf_putstr((SBuf *)sbx, strV(o));
117 } else if (tvisint(o)) {
118 lj_strfmt_putint((SBuf *)sbx, intV(o));
119 } else if (tvisnum(o)) {
120 lj_strfmt_putfnum((SBuf *)sbx, STRFMT_G14, numV(o));
121 } else if (tvisbuf(o)) {
122 SBufExt *sbx2 = bufV(o);
123 lj_buf_putmem((SBuf *)sbx, sbx2->r, sbufxlen(sbx2));
124 } else if (!mo && !tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
125 /* Call __tostring metamethod inline. */
126 copyTV(L, L->top++, mo);
127 copyTV(L, L->top++, o);
128 lua_call(L, 1, 1);
129 o = &L->base[arg]; /* The stack may have been reallocated. */
130 copyTV(L, &L->base[arg], L->top-1);
131 L->top = L->base + narg;
132 goto retry; /* Retry with the result. */
133 } else {
134 lj_err_argtype(L, arg+1, "string/number/__tostring");
135 }
136 /* Probably not useful to inline other __tostring MMs, e.g. FFI numbers. */
137 }
138 L->top = L->base+1; /* Chain buffer object. */
139 lj_gc_check(L);
140 return 1;
141}
142
143LJLIB_CF(buffer_method_putf)
144{
145 SBufExt *sbx = buffer_tobufw(L);
146 lj_strfmt_putarg(L, (SBuf *)sbx, 2, 2);
147 L->top = L->base+1; /* Chain buffer object. */
148 lj_gc_check(L);
149 return 1;
150}
151
152LJLIB_CF(buffer_method_get)
153{
154 SBufExt *sbx = buffer_tobuf(L);
155 ptrdiff_t arg, narg = L->top - L->base;
156 if (narg == 1) {
157 narg++;
158 setnilV(L->top++); /* get() is the same as get(nil). */
159 }
160 for (arg = 1; arg < narg; arg++) {
161 TValue *o = &L->base[arg];
162 MSize n = tvisnil(o) ? LJ_MAX_BUF :
163 (MSize) lj_lib_checkintrange(L, arg+1, 0, LJ_MAX_BUF);
164 MSize len = sbufxlen(sbx);
165 if (n > len) n = len;
166 setstrV(L, o, lj_str_new(L, sbx->r, n));
167 sbx->r += n;
168 }
169 if (sbx->r == sbx->w) sbx->r = sbx->w = sbx->b;
170 lj_gc_check(L);
171 return narg-1;
172}
173
174#if LJ_HASFFI
175LJLIB_CF(buffer_method_putcdata)
176{
177 SBufExt *sbx = buffer_tobufw(L);
178 const char *p;
179 MSize len;
180 if (tviscdata(L->base+1)) {
181 CTState *cts = ctype_cts(L);
182 lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
183 L->base+1, CCF_ARG(2));
184 } else {
185 lj_err_argtype(L, 2, "cdata");
186 }
187 len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
188 lj_buf_putmem((SBuf *)sbx, p, len);
189 L->top = L->base+1; /* Chain buffer object. */
190 return 1;
191}
192
193LJLIB_CF(buffer_method_reserve)
194{
195 SBufExt *sbx = buffer_tobufw(L);
196 MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
197 GCcdata *cd;
198 lj_buf_more((SBuf *)sbx, len);
199 ctype_loadffi(L);
200 cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
201 *(void **)cdataptr(cd) = sbx->w;
202 setcdataV(L, L->top++, cd);
203 setintV(L->top++, sbufleft(sbx));
204 return 2;
205}
206
207LJLIB_CF(buffer_method_commit)
208{
209 SBufExt *sbx = buffer_tobuf(L);
210 MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
211 if (len > sbufleft(sbx)) lj_err_arg(L, 2, LJ_ERR_NUMRNG);
212 sbx->w += len;
213 L->top = L->base+1; /* Chain buffer object. */
214 return 1;
215}
216
217LJLIB_CF(buffer_method_ref)
218{
219 SBufExt *sbx = buffer_tobuf(L);
220 GCcdata *cd;
221 ctype_loadffi(L);
222 cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
223 *(void **)cdataptr(cd) = sbx->r;
224 setcdataV(L, L->top++, cd);
225 setintV(L->top++, sbufxlen(sbx));
226 return 2;
227}
228#endif
229
230LJLIB_CF(buffer_method_encode)
231{
232 SBufExt *sbx = buffer_tobufw(L);
233 cTValue *o = lj_lib_checkany(L, 2);
234 lj_serialize_put(sbx, o);
235 lj_gc_check(L);
236 L->top = L->base+1; /* Chain buffer object. */
237 return 1;
238}
239
240LJLIB_CF(buffer_method_decode)
241{
242 SBufExt *sbx = buffer_tobufw(L);
243 setnilV(L->top++);
244 lj_serialize_get(sbx, L->top-1);
245 lj_gc_check(L);
246 return 1;
247}
248
249LJLIB_CF(buffer_method___gc)
250{
251 SBufExt *sbx = buffer_tobuf(L);
252 lj_bufx_free(G(L), sbx);
253 lj_bufx_init(L, sbx);
254 return 0;
255}
256
257LJLIB_CF(buffer_method___tostring)
258{
259 SBufExt *sbx = buffer_tobuf(L);
260 setstrV(L, L->top-1, lj_str_new(L, sbx->r, sbufxlen(sbx)));
261 lj_gc_check(L);
262 return 1;
263}
264
265LJLIB_CF(buffer_method___len)
266{
267 SBufExt *sbx = buffer_tobuf(L);
268 setintV(L->top-1, (int32_t)sbufxlen(sbx));
269 return 1;
270}
271
272LJLIB_PUSH("buffer") LJLIB_SET(__metatable)
273LJLIB_PUSH(top-1) LJLIB_SET(__index)
274
275/* ------------------------------------------------------------------------ */
276
23#define LJLIB_MODULE_buffer 277#define LJLIB_MODULE_buffer
24 278
279LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */
280
281LJLIB_CF(buffer_new)
282{
283 MSize sz = L->base == L->top ? 0u :
284 (MSize)lj_lib_checkintrange(L, 1, 0, LJ_MAX_BUF);
285 GCtab *env = tabref(curr_func(L)->c.env);
286 GCudata *ud = lj_udata_new(L, sizeof(SBufExt), env);
287 SBufExt *sbx = (SBufExt *)uddata(ud);
288 ud->udtype = UDTYPE_BUFFER;
289 /* NOBARRIER: The GCudata is new (marked white). */
290 setgcref(ud->metatable, obj2gco(env));
291 setudataV(L, L->top++, ud);
292 lj_bufx_init(L, sbx);
293 if (sz > 0) lj_buf_need2((SBuf *)sbx, sz);
294 return 1;
295}
296
25LJLIB_CF(buffer_encode) 297LJLIB_CF(buffer_encode)
26{ 298{
27 cTValue *o = lj_lib_checkany(L, 1); 299 cTValue *o = lj_lib_checkany(L, 1);
@@ -35,13 +307,14 @@ LJLIB_CF(buffer_encode)
35 307
36LJLIB_CF(buffer_decode) 308LJLIB_CF(buffer_decode)
37{ 309{
38 GCstr *str = lj_lib_checkstr(L, 1); 310 GCstr *str = lj_lib_checkstrx(L, 1);
39 SBufExt sbx; 311 SBufExt sbx;
40 lj_bufx_init_cow(L, &sbx, strdata(str), str->len); 312 lj_bufx_init_cow(L, &sbx, strdata(str), str->len);
41 /* No need to set sbx.cowref here. */ 313 /* No need to set sbx.cowref here. */
42 setnilV(L->top++); 314 setnilV(L->top++);
43 lj_serialize_get(&sbx, L->top-1); 315 lj_serialize_get(&sbx, L->top-1);
44 lj_gc_check(L); 316 lj_gc_check(L);
317 if (sbx.r != sbx.w) lj_err_caller(L, LJ_ERR_BUFFER_LEFTOV);
45 return 1; 318 return 1;
46} 319}
47 320
@@ -51,6 +324,9 @@ LJLIB_CF(buffer_decode)
51 324
52int luaopen_string_buffer(lua_State *L) 325int luaopen_string_buffer(lua_State *L)
53{ 326{
327 LJ_LIB_REG(L, NULL, buffer_method);
328 lua_getfield(L, -1, "__tostring");
329 lua_setfield(L, -2, "tostring");
54 LJ_LIB_REG(L, NULL, buffer); 330 LJ_LIB_REG(L, NULL, buffer);
55 return 1; 331 return 1;
56} 332}